~ubuntu-branches/debian/jessie/sqlalchemy/jessie

« back to all changes in this revision

Viewing changes to lib/sqlalchemy/orm/session.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski, Jakub Wilk, Piotr Ożarowski
  • Date: 2013-07-06 20:53:52 UTC
  • mfrom: (1.4.23) (16.1.17 experimental)
  • Revision ID: package-import@ubuntu.com-20130706205352-ryppl1eto3illd79
Tags: 0.8.2-1
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Piotr Ożarowski ]
* New upstream release
* Upload to unstable
* Build depend on python3-all instead of -dev, extensions are not built for
  Python 3.X 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# orm/session.py
2
 
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
 
2
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
3
3
#
4
4
# This module is part of SQLAlchemy and is released under
5
5
# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
 
 
7
6
"""Provides the Session class and related utilities."""
8
7
 
 
8
from __future__ import with_statement
 
9
 
9
10
import weakref
10
 
from itertools import chain
11
 
from sqlalchemy import util, sql, engine, log, exc as sa_exc
12
 
from sqlalchemy.sql import util as sql_util, expression
13
 
from sqlalchemy.orm import (
14
 
    SessionExtension, attributes, exc, query, unitofwork, util as mapperutil, state
15
 
    )
16
 
from sqlalchemy.orm.util import object_mapper as _object_mapper
17
 
from sqlalchemy.orm.util import class_mapper as _class_mapper
18
 
from sqlalchemy.orm.util import (
19
 
    _class_to_mapper, _state_mapper,
20
 
    )
21
 
from sqlalchemy.orm.mapper import Mapper, _none_set
22
 
from sqlalchemy.orm.unitofwork import UOWTransaction
23
 
from sqlalchemy.orm import identity
24
 
from sqlalchemy import event
25
 
from sqlalchemy.orm.events import SessionEvents
26
 
 
 
11
from .. import util, sql, engine, exc as sa_exc, event
 
12
from ..sql import util as sql_util, expression
 
13
from . import (
 
14
    SessionExtension, attributes, exc, query, util as orm_util,
 
15
    loading, identity
 
16
    )
 
17
from .util import (
 
18
    object_mapper, class_mapper,
 
19
    _class_to_mapper, _state_mapper, object_state,
 
20
    _none_set
 
21
    )
 
22
from .unitofwork import UOWTransaction
 
23
from .mapper import Mapper
 
24
from .events import SessionEvents
 
25
statelib = util.importlater("sqlalchemy.orm", "state")
27
26
import sys
28
27
 
29
 
__all__ = ['Session', 'SessionTransaction', 'SessionExtension']
30
 
 
31
 
 
32
 
def sessionmaker(bind=None, class_=None, autoflush=True, autocommit=False,
33
 
                 expire_on_commit=True, **kwargs):
34
 
    """Generate a custom-configured :class:`.Session` class.
35
 
 
36
 
    The returned object is a subclass of :class:`.Session`, which, when instantiated
37
 
    with no arguments, uses the keyword arguments configured here as its
38
 
    constructor arguments.
39
 
 
40
 
    It is intended that the :func:`.sessionmaker()` function be called within the
41
 
    global scope of an application, and the returned class be made available
42
 
    to the rest of the application as the single class used to instantiate
43
 
    sessions.
44
 
 
45
 
    e.g.::
46
 
 
47
 
        # global scope
48
 
        Session = sessionmaker(autoflush=False)
49
 
 
50
 
        # later, in a local scope, create and use a session:
51
 
        sess = Session()
52
 
 
53
 
    Any keyword arguments sent to the constructor itself will override the
54
 
    "configured" keywords::
55
 
 
56
 
        Session = sessionmaker()
57
 
 
58
 
        # bind an individual session to a connection
59
 
        sess = Session(bind=connection)
60
 
 
61
 
    The class also includes a special classmethod ``configure()``, which
62
 
    allows additional configurational options to take place after the custom
63
 
    ``Session`` class has been generated.  This is useful particularly for
64
 
    defining the specific ``Engine`` (or engines) to which new instances of
65
 
    ``Session`` should be bound::
66
 
 
67
 
        Session = sessionmaker()
68
 
        Session.configure(bind=create_engine('sqlite:///foo.db'))
69
 
 
70
 
        sess = Session()
71
 
 
72
 
    For options, see the constructor options for :class:`.Session`.
73
 
 
74
 
    """
75
 
    kwargs['bind'] = bind
76
 
    kwargs['autoflush'] = autoflush
77
 
    kwargs['autocommit'] = autocommit
78
 
    kwargs['expire_on_commit'] = expire_on_commit
79
 
 
80
 
    if class_ is None:
81
 
        class_ = Session
82
 
 
83
 
    class Sess(object):
84
 
        def __init__(self, **local_kwargs):
85
 
            for k in kwargs:
86
 
                local_kwargs.setdefault(k, kwargs[k])
87
 
            super(Sess, self).__init__(**local_kwargs)
88
 
 
89
 
        @classmethod
90
 
        def configure(self, **new_kwargs):
91
 
            """(Re)configure the arguments for this sessionmaker.
92
 
 
93
 
            e.g.::
94
 
 
95
 
                Session = sessionmaker()
96
 
 
97
 
                Session.configure(bind=create_engine('sqlite://'))
98
 
            """
99
 
            kwargs.update(new_kwargs)
100
 
 
101
 
 
102
 
    return type("SessionMaker", (Sess, class_), {})
103
 
 
 
28
__all__ = ['Session', 'SessionTransaction', 'SessionExtension', 'sessionmaker']
 
29
 
 
30
 
 
31
class _SessionClassMethods(object):
 
32
    """Class-level methods for :class:`.Session`, :class:`.sessionmaker`."""
 
33
 
 
34
    @classmethod
 
35
    def close_all(cls):
 
36
        """Close *all* sessions in memory."""
 
37
 
 
38
        for sess in _sessions.values():
 
39
            sess.close()
 
40
 
 
41
    @classmethod
 
42
    def identity_key(cls, *args, **kwargs):
 
43
        """Return an identity key.
 
44
 
 
45
        This is an alias of :func:`.util.identity_key`.
 
46
 
 
47
        """
 
48
        return orm_util.identity_key(*args, **kwargs)
 
49
 
 
50
    @classmethod
 
51
    def object_session(cls, instance):
 
52
        """Return the :class:`.Session` to which an object belongs.
 
53
 
 
54
        This is an alias of :func:`.object_session`.
 
55
 
 
56
        """
 
57
 
 
58
        return object_session(instance)
 
59
 
 
60
 
 
61
ACTIVE = util.symbol('ACTIVE')
 
62
PREPARED = util.symbol('PREPARED')
 
63
COMMITTED = util.symbol('COMMITTED')
 
64
DEACTIVE = util.symbol('DEACTIVE')
 
65
CLOSED = util.symbol('CLOSED')
104
66
 
105
67
class SessionTransaction(object):
106
68
    """A :class:`.Session`-level transaction.
112
74
    back all at once.   It also provides optional two-phase commit behavior
113
75
    which can augment this coordination operation.
114
76
 
115
 
    The :attr:`.Session.transaction` attribute of :class:`.Session` refers to the
116
 
    current :class:`.SessionTransaction` object in use, if any.
 
77
    The :attr:`.Session.transaction` attribute of :class:`.Session`
 
78
    refers to the current :class:`.SessionTransaction` object in use, if any.
117
79
 
118
80
 
119
81
    A :class:`.SessionTransaction` is associated with a :class:`.Session`
120
82
    in its default mode of ``autocommit=False`` immediately, associated
121
83
    with no database connections.  As the :class:`.Session` is called upon
122
84
    to emit SQL on behalf of various :class:`.Engine` or :class:`.Connection`
123
 
    objects, a corresponding :class:`.Connection` and associated :class:`.Transaction`
124
 
    is added to a collection within the :class:`.SessionTransaction` object,
125
 
    becoming one of the connection/transaction pairs maintained by the
 
85
    objects, a corresponding :class:`.Connection` and associated
 
86
    :class:`.Transaction` is added to a collection within the
 
87
    :class:`.SessionTransaction` object, becoming one of the
 
88
    connection/transaction pairs maintained by the
126
89
    :class:`.SessionTransaction`.
127
90
 
128
91
    The lifespan of the :class:`.SessionTransaction` ends when the
129
 
    :meth:`.Session.commit`, :meth:`.Session.rollback` or :meth:`.Session.close`
130
 
    methods are called.  At this point, the :class:`.SessionTransaction` removes
131
 
    its association with its parent :class:`.Session`.   A :class:`.Session`
132
 
    that is in ``autocommit=False`` mode will create a new
133
 
    :class:`.SessionTransaction` to replace it immediately, whereas a
134
 
    :class:`.Session` that's in ``autocommit=True``
 
92
    :meth:`.Session.commit`, :meth:`.Session.rollback` or
 
93
    :meth:`.Session.close` methods are called.  At this point, the
 
94
    :class:`.SessionTransaction` removes its association with its parent
 
95
    :class:`.Session`.   A :class:`.Session` that is in ``autocommit=False``
 
96
    mode will create a new :class:`.SessionTransaction` to replace it
 
97
    immediately, whereas a :class:`.Session` that's in ``autocommit=True``
135
98
    mode will remain without a :class:`.SessionTransaction` until the
136
99
    :meth:`.Session.begin` method is called.
137
100
 
138
101
    Another detail of :class:`.SessionTransaction` behavior is that it is
139
 
    capable of "nesting".  This means that the :meth:`.begin` method can
140
 
    be called while an existing :class:`.SessionTransaction` is already present,
141
 
    producing a new :class:`.SessionTransaction` that temporarily replaces
142
 
    the parent :class:`.SessionTransaction`.   When a :class:`.SessionTransaction`
143
 
    is produced as nested, it assigns itself to the :attr:`.Session.transaction`
144
 
    attribute.  When it is ended via :meth:`.Session.commit` or :meth:`.Session.rollback`,
145
 
    it restores its parent :class:`.SessionTransaction` back onto the
146
 
    :attr:`.Session.transaction` attribute.  The
147
 
    behavior is effectively a stack, where :attr:`.Session.transaction` refers
148
 
    to the current head of the stack.
 
102
    capable of "nesting".  This means that the :meth:`.Session.begin` method
 
103
    can be called while an existing :class:`.SessionTransaction` is already
 
104
    present, producing a new :class:`.SessionTransaction` that temporarily
 
105
    replaces the parent :class:`.SessionTransaction`.   When a
 
106
    :class:`.SessionTransaction` is produced as nested, it assigns itself to
 
107
    the :attr:`.Session.transaction` attribute.  When it is ended via
 
108
    :meth:`.Session.commit` or :meth:`.Session.rollback`, it restores its
 
109
    parent :class:`.SessionTransaction` back onto the
 
110
    :attr:`.Session.transaction` attribute.  The behavior is effectively a
 
111
    stack, where :attr:`.Session.transaction` refers to the current head of
 
112
    the stack.
149
113
 
150
 
    The purpose of this stack is to allow nesting of :meth:`.rollback` or
151
 
    :meth:`.commit` calls in context with various flavors of :meth:`.begin`.
152
 
    This nesting behavior applies to when :meth:`.Session.begin_nested`
153
 
    is used to emit a SAVEPOINT transaction, and is also used to produce
154
 
    a so-called "subtransaction" which allows a block of code to use a
 
114
    The purpose of this stack is to allow nesting of
 
115
    :meth:`.Session.rollback` or :meth:`.Session.commit` calls in context
 
116
    with various flavors of :meth:`.Session.begin`. This nesting behavior
 
117
    applies to when :meth:`.Session.begin_nested` is used to emit a
 
118
    SAVEPOINT transaction, and is also used to produce a so-called
 
119
    "subtransaction" which allows a block of code to use a
155
120
    begin/rollback/commit sequence regardless of whether or not its enclosing
156
 
    code block has begun a transaction.  The :meth:`.flush` method, whether called
157
 
    explicitly or via autoflush, is the primary consumer of the "subtransaction"
158
 
    feature, in that it wishes to guarantee that it works within in a transaction block
159
 
    regardless of whether or not the :class:`.Session` is in transactional mode
160
 
    when the method is called.
 
121
    code block has begun a transaction.  The :meth:`.flush` method, whether
 
122
    called explicitly or via autoflush, is the primary consumer of the
 
123
    "subtransaction" feature, in that it wishes to guarantee that it works
 
124
    within in a transaction block regardless of whether or not the
 
125
    :class:`.Session` is in transactional mode when the method is called.
161
126
 
162
127
    See also:
163
128
 
186
151
        self._connections = {}
187
152
        self._parent = parent
188
153
        self.nested = nested
189
 
        self._active = True
190
 
        self._prepared = False
 
154
        self._state = ACTIVE
191
155
        if not parent and nested:
192
156
            raise sa_exc.InvalidRequestError(
193
157
                "Can't start a SAVEPOINT transaction when no existing "
196
160
        if self.session._enable_transaction_accounting:
197
161
            self._take_snapshot()
198
162
 
 
163
        if self.session.dispatch.after_transaction_create:
 
164
            self.session.dispatch.after_transaction_create(self.session, self)
 
165
 
199
166
    @property
200
167
    def is_active(self):
201
 
        return self.session is not None and self._active
 
168
        return self.session is not None and self._state is ACTIVE
202
169
 
203
 
    def _assert_is_active(self):
204
 
        self._assert_is_open()
205
 
        if not self._active:
206
 
            if self._rollback_exception:
207
 
                raise sa_exc.InvalidRequestError(
208
 
                    "This Session's transaction has been rolled back "
209
 
                    "due to a previous exception during flush."
210
 
                    " To begin a new transaction with this Session, "
211
 
                    "first issue Session.rollback()."
212
 
                    " Original exception was: %s"
213
 
                    % self._rollback_exception
 
170
    def _assert_active(self, prepared_ok=False,
 
171
                        rollback_ok=False,
 
172
                        deactive_ok=False,
 
173
                        closed_msg="This transaction is closed"):
 
174
        if self._state is COMMITTED:
 
175
            raise sa_exc.InvalidRequestError(
 
176
                    "This session is in 'committed' state; no further "
 
177
                    "SQL can be emitted within this transaction."
214
178
                )
215
 
            else:
 
179
        elif self._state is PREPARED:
 
180
            if not prepared_ok:
216
181
                raise sa_exc.InvalidRequestError(
217
 
                    "This Session's transaction has been rolled back "
218
 
                    "by a nested rollback() call.  To begin a new "
219
 
                    "transaction, issue Session.rollback() first."
220
 
                    )
221
 
 
222
 
    def _assert_is_open(self, error_msg="The transaction is closed"):
223
 
        if self.session is None:
224
 
            raise sa_exc.ResourceClosedError(error_msg)
 
182
                        "This session is in 'prepared' state; no further "
 
183
                        "SQL can be emitted within this transaction."
 
184
                    )
 
185
        elif self._state is DEACTIVE:
 
186
            if not deactive_ok and not rollback_ok:
 
187
                if self._rollback_exception:
 
188
                    raise sa_exc.InvalidRequestError(
 
189
                        "This Session's transaction has been rolled back "
 
190
                        "due to a previous exception during flush."
 
191
                        " To begin a new transaction with this Session, "
 
192
                        "first issue Session.rollback()."
 
193
                        " Original exception was: %s"
 
194
                        % self._rollback_exception
 
195
                    )
 
196
                elif not deactive_ok:
 
197
                    raise sa_exc.InvalidRequestError(
 
198
                        "This Session's transaction has been rolled back "
 
199
                        "by a nested rollback() call.  To begin a new "
 
200
                        "transaction, issue Session.rollback() first."
 
201
                        )
 
202
        elif self._state is CLOSED:
 
203
            raise sa_exc.ResourceClosedError(closed_msg)
225
204
 
226
205
    @property
227
206
    def _is_transaction_boundary(self):
228
207
        return self.nested or not self._parent
229
208
 
230
209
    def connection(self, bindkey, **kwargs):
231
 
        self._assert_is_active()
232
 
        engine = self.session.get_bind(bindkey, **kwargs)
233
 
        return self._connection_for_bind(engine)
 
210
        self._assert_active()
 
211
        bind = self.session.get_bind(bindkey, **kwargs)
 
212
        return self._connection_for_bind(bind)
234
213
 
235
214
    def _begin(self, nested=False):
236
 
        self._assert_is_active()
 
215
        self._assert_active()
237
216
        return SessionTransaction(
238
217
            self.session, self, nested=nested)
239
218
 
251
230
        if not self._is_transaction_boundary:
252
231
            self._new = self._parent._new
253
232
            self._deleted = self._parent._deleted
 
233
            self._dirty = self._parent._dirty
 
234
            self._key_switches = self._parent._key_switches
254
235
            return
255
236
 
256
237
        if not self.session._flushing:
258
239
 
259
240
        self._new = weakref.WeakKeyDictionary()
260
241
        self._deleted = weakref.WeakKeyDictionary()
 
242
        self._dirty = weakref.WeakKeyDictionary()
 
243
        self._key_switches = weakref.WeakKeyDictionary()
261
244
 
262
 
    def _restore_snapshot(self):
 
245
    def _restore_snapshot(self, dirty_only=False):
263
246
        assert self._is_transaction_boundary
264
247
 
265
248
        for s in set(self._new).union(self.session._new):
267
250
            if s.key:
268
251
                del s.key
269
252
 
 
253
        for s, (oldkey, newkey) in self._key_switches.items():
 
254
            self.session.identity_map.discard(s)
 
255
            s.key = oldkey
 
256
            self.session.identity_map.replace(s)
 
257
 
270
258
        for s in set(self._deleted).union(self.session._deleted):
271
259
            if s.deleted:
272
260
                #assert s in self._deleted
273
261
                del s.deleted
274
 
            self.session._update_impl(s)
 
262
            self.session._update_impl(s, discard_existing=True)
275
263
 
276
264
        assert not self.session._deleted
277
265
 
278
266
        for s in self.session.identity_map.all_states():
279
 
            s.expire(s.dict, self.session.identity_map._modified)
 
267
            if not dirty_only or s.modified or s in self._dirty:
 
268
                s._expire(s.dict, self.session.identity_map._modified)
280
269
 
281
270
    def _remove_snapshot(self):
282
271
        assert self._is_transaction_boundary
283
272
 
284
273
        if not self.nested and self.session.expire_on_commit:
285
274
            for s in self.session.identity_map.all_states():
286
 
                s.expire(s.dict, self.session.identity_map._modified)
 
275
                s._expire(s.dict, self.session.identity_map._modified)
 
276
            for s in self._deleted:
 
277
                s.session_id = None
 
278
            self._deleted.clear()
 
279
 
287
280
 
288
281
    def _connection_for_bind(self, bind):
289
 
        self._assert_is_active()
 
282
        self._assert_active()
290
283
 
291
284
        if bind in self._connections:
292
285
            return self._connections[bind][0]
320
313
    def prepare(self):
321
314
        if self._parent is not None or not self.session.twophase:
322
315
            raise sa_exc.InvalidRequestError(
323
 
                "Only root two phase transactions of can be prepared")
 
316
                "'twophase' mode not enabled, or not root transaction; "
 
317
                "can't prepare.")
324
318
        self._prepare_impl()
325
319
 
326
320
    def _prepare_impl(self):
327
 
        self._assert_is_active()
 
321
        self._assert_active()
328
322
        if self._parent is None or self.nested:
329
323
            self.session.dispatch.before_commit(self.session)
330
324
 
349
343
                for t in set(self._connections.values()):
350
344
                    t[1].prepare()
351
345
            except:
352
 
                self.rollback()
353
 
                raise
 
346
                with util.safe_reraise():
 
347
                    self.rollback()
354
348
 
355
 
        self._deactivate()
356
 
        self._prepared = True
 
349
        self._state = PREPARED
357
350
 
358
351
    def commit(self):
359
 
        self._assert_is_open()
360
 
        if not self._prepared:
 
352
        self._assert_active(prepared_ok=True)
 
353
        if self._state is not PREPARED:
361
354
            self._prepare_impl()
362
355
 
363
356
        if self._parent is None or self.nested:
364
357
            for t in set(self._connections.values()):
365
358
                t[1].commit()
366
359
 
 
360
            self._state = COMMITTED
367
361
            self.session.dispatch.after_commit(self.session)
368
362
 
369
363
            if self.session._enable_transaction_accounting:
373
367
        return self._parent
374
368
 
375
369
    def rollback(self, _capture_exception=False):
376
 
        self._assert_is_open()
 
370
        self._assert_active(prepared_ok=True, rollback_ok=True)
377
371
 
378
372
        stx = self.session.transaction
379
373
        if stx is not self:
380
374
            for subtransaction in stx._iterate_parents(upto=self):
381
375
                subtransaction.close()
382
376
 
383
 
        if self.is_active or self._prepared:
 
377
        if self._state in (ACTIVE, PREPARED):
384
378
            for transaction in self._iterate_parents():
385
379
                if transaction._parent is None or transaction.nested:
386
380
                    transaction._rollback_impl()
387
 
                    transaction._deactivate()
 
381
                    transaction._state = DEACTIVE
388
382
                    break
389
383
                else:
390
 
                    transaction._deactivate()
 
384
                    transaction._state = DEACTIVE
391
385
 
392
386
        sess = self.session
393
387
 
394
388
        if self.session._enable_transaction_accounting and \
395
 
            not sess._is_clean():
 
389
                not sess._is_clean():
396
390
            # if items were added, deleted, or mutated
397
391
            # here, we need to re-restore the snapshot
398
392
            util.warn(
399
393
                    "Session's state has been changed on "
400
394
                    "a non-active transaction - this state "
401
395
                    "will be discarded.")
402
 
            self._restore_snapshot()
 
396
            self._restore_snapshot(dirty_only=self.nested)
403
397
 
404
398
        self.close()
405
399
        if self._parent and _capture_exception:
414
408
            t[1].rollback()
415
409
 
416
410
        if self.session._enable_transaction_accounting:
417
 
            self._restore_snapshot()
 
411
            self._restore_snapshot(dirty_only=self.nested)
418
412
 
419
413
        self.session.dispatch.after_rollback(self.session)
420
414
 
421
 
    def _deactivate(self):
422
 
        self._active = False
423
 
 
424
415
    def close(self):
425
416
        self.session.transaction = self._parent
426
417
        if self._parent is None:
427
418
            for connection, transaction, autoclose in \
428
 
                set(self._connections.values()):
 
419
                    set(self._connections.values()):
429
420
                if autoclose:
430
421
                    connection.close()
431
422
                else:
432
423
                    transaction.close()
 
424
 
 
425
        self._state = CLOSED
 
426
        if self.session.dispatch.after_transaction_end:
 
427
            self.session.dispatch.after_transaction_end(self.session, self)
 
428
 
 
429
        if self._parent is None:
433
430
            if not self.session.autocommit:
434
431
                self.session.begin()
435
 
        self._deactivate()
436
432
        self.session = None
437
433
        self._connections = None
438
434
 
440
436
        return self
441
437
 
442
438
    def __exit__(self, type, value, traceback):
443
 
        self._assert_is_open("Cannot end transaction context. The transaction "
444
 
                                    "was closed from within the context")
 
439
        self._assert_active(deactive_ok=True, prepared_ok=True)
445
440
        if self.session.transaction is None:
446
441
            return
447
442
        if type is None:
448
443
            try:
449
444
                self.commit()
450
445
            except:
451
 
                self.rollback()
452
 
                raise
 
446
                with util.safe_reraise():
 
447
                    self.rollback()
453
448
        else:
454
449
            self.rollback()
455
450
 
456
 
class Session(object):
 
451
 
 
452
class Session(_SessionClassMethods):
457
453
    """Manages persistence operations for ORM-mapped objects.
458
454
 
459
 
    The Session's usage paradigm is described at :ref:`session_toplevel`.
 
455
    The Session's usage paradigm is described at :doc:`/orm/session`.
460
456
 
461
457
 
462
458
    """
469
465
        'merge', 'query', 'refresh', 'rollback',
470
466
        'scalar')
471
467
 
472
 
 
473
468
    def __init__(self, bind=None, autoflush=True, expire_on_commit=True,
474
469
                _enable_transaction_accounting=True,
475
470
                 autocommit=False, twophase=False,
477
472
                 query_cls=query.Query):
478
473
        """Construct a new Session.
479
474
 
480
 
        See also the :func:`.sessionmaker` function which is used to
 
475
        See also the :class:`.sessionmaker` function which is used to
481
476
        generate a :class:`.Session`-producing callable with a given
482
477
        set of arguments.
483
478
 
484
 
        :param autocommit: Defaults to ``False``. When ``True``, the ``Session``
485
 
          does not keep a persistent transaction running, and will acquire
486
 
          connections from the engine on an as-needed basis, returning them
487
 
          immediately after their use. Flushes will begin and commit (or possibly
488
 
          rollback) their own transaction if no transaction is present. When using
489
 
          this mode, the `session.begin()` method may be used to begin a
490
 
          transaction explicitly.
491
 
 
492
 
          Leaving it on its default value of ``False`` means that the ``Session``
493
 
          will acquire a connection and begin a transaction the first time it is
494
 
          used, which it will maintain persistently until ``rollback()``,
495
 
          ``commit()``, or ``close()`` is called. When the transaction is released
496
 
          by any of these methods, the ``Session`` is ready for the next usage,
497
 
          which will again acquire and maintain a new connection/transaction.
 
479
        :param autocommit:
 
480
 
 
481
          .. warning::
 
482
 
 
483
             The autocommit flag is **not for general use**, and if it is used,
 
484
             queries should only be invoked within the span of a
 
485
             :meth:`.Session.begin` / :meth:`.Session.commit` pair.   Executing
 
486
             queries outside of a demarcated transaction is a legacy mode
 
487
             of usage, and can in some cases lead to concurrent connection
 
488
             checkouts.
 
489
 
 
490
          Defaults to ``False``. When ``True``, the
 
491
          :class:`.Session` does not keep a persistent transaction running, and
 
492
          will acquire connections from the engine on an as-needed basis,
 
493
          returning them immediately after their use. Flushes will begin and
 
494
          commit (or possibly rollback) their own transaction if no
 
495
          transaction is present. When using this mode, the
 
496
          :meth:`.Session.begin` method is used to explicitly start
 
497
          transactions.
 
498
 
 
499
          .. seealso::
 
500
 
 
501
            :ref:`session_autocommit`
498
502
 
499
503
        :param autoflush: When ``True``, all query operations will issue a
500
504
           ``flush()`` call to this ``Session`` before proceeding. This is a
501
 
           convenience feature so that ``flush()`` need not be called repeatedly
502
 
           in order for database queries to retrieve results. It's typical that
503
 
           ``autoflush`` is used in conjunction with ``autocommit=False``. In this
504
 
           scenario, explicit calls to ``flush()`` are rarely needed; you usually
505
 
           only need to call ``commit()`` (which flushes) to finalize changes.
 
505
           convenience feature so that ``flush()`` need not be called
 
506
           repeatedly in order for database queries to retrieve results. It's
 
507
           typical that ``autoflush`` is used in conjunction with
 
508
           ``autocommit=False``. In this scenario, explicit calls to
 
509
           ``flush()`` are rarely needed; you usually only need to call
 
510
           ``commit()`` (which flushes) to finalize changes.
506
511
 
507
512
        :param bind: An optional ``Engine`` or ``Connection`` to which this
508
513
           ``Session`` should be bound. When specified, all SQL operations
509
514
           performed by this session will execute via this connectable.
510
515
 
511
 
        :param binds: An optional dictionary which contains more granular "bind"
512
 
           information than the ``bind`` parameter provides. This dictionary can
513
 
           map individual ``Table`` instances as well as ``Mapper`` instances to
514
 
           individual ``Engine`` or ``Connection`` objects. Operations which
515
 
           proceed relative to a particular ``Mapper`` will consult this
516
 
           dictionary for the direct ``Mapper`` instance as well as the mapper's
517
 
           ``mapped_table`` attribute in order to locate an connectable to use.
518
 
           The full resolution is described in the ``get_bind()`` method of
519
 
           ``Session``. Usage looks like::
 
516
        :param binds: An optional dictionary which contains more granular
 
517
           "bind" information than the ``bind`` parameter provides. This
 
518
           dictionary can map individual ``Table`` instances as well as
 
519
           ``Mapper`` instances to individual ``Engine`` or ``Connection``
 
520
           objects. Operations which proceed relative to a particular
 
521
           ``Mapper`` will consult this dictionary for the direct ``Mapper``
 
522
           instance as well as the mapper's ``mapped_table`` attribute in
 
523
           order to locate an connectable to use. The full resolution is
 
524
           described in the ``get_bind()`` method of ``Session``.
 
525
           Usage looks like::
520
526
 
521
527
            Session = sessionmaker(binds={
522
528
                SomeMappedClass: create_engine('postgresql://engine1'),
524
530
                some_table: create_engine('postgresql://engine3'),
525
531
                })
526
532
 
527
 
          Also see the :meth:`.Session.bind_mapper` and :meth:`.Session.bind_table` methods.
 
533
          Also see the :meth:`.Session.bind_mapper`
 
534
          and :meth:`.Session.bind_table` methods.
528
535
 
529
536
        :param \class_: Specify an alternate class other than
530
 
           ``sqlalchemy.orm.session.Session`` which should be used by the returned
531
 
           class. This is the only argument that is local to the
 
537
           ``sqlalchemy.orm.session.Session`` which should be used by the
 
538
           returned class. This is the only argument that is local to the
532
539
           ``sessionmaker()`` function, and is not sent directly to the
533
540
           constructor for ``Session``.
534
541
 
535
542
        :param _enable_transaction_accounting:  Defaults to ``True``.  A
536
 
           legacy-only flag which when ``False`` disables *all* 0.5-style object
537
 
           accounting on transaction boundaries, including auto-expiry of
538
 
           instances on rollback and commit, maintenance of the "new" and
 
543
           legacy-only flag which when ``False`` disables *all* 0.5-style
 
544
           object accounting on transaction boundaries, including auto-expiry
 
545
           of instances on rollback and commit, maintenance of the "new" and
539
546
           "deleted" lists upon rollback, and autoflush of pending changes upon
540
547
           begin(), all of which are interdependent.
541
548
 
542
549
        :param expire_on_commit:  Defaults to ``True``. When ``True``, all
543
 
           instances will be fully expired after each ``commit()``, so that all
544
 
           attribute/object access subsequent to a completed transaction will load
545
 
           from the most recent database state.
 
550
           instances will be fully expired after each ``commit()``, so that
 
551
           all attribute/object access subsequent to a completed transaction
 
552
           will load from the most recent database state.
546
553
 
547
554
        :param extension: An optional
548
555
           :class:`~.SessionExtension` instance, or a list
549
 
           of such instances, which will receive pre- and post- commit and flush
550
 
           events, as well as a post-rollback event. **Deprecated.**
 
556
           of such instances, which will receive pre- and post- commit and
 
557
           flush events, as well as a post-rollback event. **Deprecated.**
551
558
           Please see :class:`.SessionEvents`.
552
559
 
553
 
        :param query_cls:  Class which should be used to create new Query objects,
554
 
           as returned by the ``query()`` method. Defaults to
 
560
        :param query_cls:  Class which should be used to create new Query
 
561
           objects, as returned by the ``query()`` method. Defaults to
555
562
           :class:`~sqlalchemy.orm.query.Query`.
556
563
 
557
564
        :param twophase:  When ``True``, all transactions will be started as
558
565
            a "two phase" transaction, i.e. using the "two phase" semantics
559
566
            of the database in use along with an XID.  During a ``commit()``,
560
567
            after ``flush()`` has been issued for all attached databases, the
561
 
            ``prepare()`` method on each database's ``TwoPhaseTransaction`` will
562
 
            be called. This allows each database to roll back the entire
 
568
            ``prepare()`` method on each database's ``TwoPhaseTransaction``
 
569
            will be called. This allows each database to roll back the entire
563
570
            transaction, before each transaction is committed.
564
571
 
565
572
        :param weak_identity_map:  Defaults to ``True`` - when set to
583
590
        self.bind = bind
584
591
        self.__binds = {}
585
592
        self._flushing = False
 
593
        self._warn_on_events = False
586
594
        self.transaction = None
587
595
        self.hash_key = _new_sessionid()
588
596
        self.autoflush = autoflush
621
629
        transaction or nested transaction, an error is raised, unless
622
630
        ``subtransactions=True`` or ``nested=True`` is specified.
623
631
 
624
 
        The ``subtransactions=True`` flag indicates that this :meth:`~.Session.begin`
625
 
        can create a subtransaction if a transaction is already in progress.
626
 
        For documentation on subtransactions, please see :ref:`session_subtransactions`.
 
632
        The ``subtransactions=True`` flag indicates that this
 
633
        :meth:`~.Session.begin` can create a subtransaction if a transaction
 
634
        is already in progress. For documentation on subtransactions, please
 
635
        see :ref:`session_subtransactions`.
627
636
 
628
637
        The ``nested`` flag begins a SAVEPOINT transaction and is equivalent
629
 
        to calling :meth:`~.Session.begin_nested`. For documentation on SAVEPOINT
630
 
        transactions, please see :ref:`session_begin_nested`.
 
638
        to calling :meth:`~.Session.begin_nested`. For documentation on
 
639
        SAVEPOINT transactions, please see :ref:`session_begin_nested`.
631
640
 
632
641
        """
633
642
        if self.transaction is not None:
636
645
                                        nested=nested)
637
646
            else:
638
647
                raise sa_exc.InvalidRequestError(
639
 
                    "A transaction is already begun.  Use subtransactions=True "
640
 
                    "to allow subtransactions.")
 
648
                    "A transaction is already begun.  Use "
 
649
                    "subtransactions=True to allow subtransactions.")
641
650
        else:
642
651
            self.transaction = SessionTransaction(
643
652
                self, nested=nested)
665
674
        to the first real transaction are closed.  Subtransactions occur when
666
675
        begin() is called multiple times.
667
676
 
 
677
        .. seealso::
 
678
 
 
679
            :ref:`session_rollback`
 
680
 
668
681
        """
669
682
        if self.transaction is None:
670
683
            pass
675
688
        """Flush pending changes and commit the current transaction.
676
689
 
677
690
        If no transaction is in progress, this method raises an
678
 
        InvalidRequestError.
 
691
        :exc:`~sqlalchemy.exc.InvalidRequestError`.
679
692
 
680
693
        By default, the :class:`.Session` also expires all database
681
694
        loaded state on all ORM-managed attributes after transaction commit.
682
695
        This so that subsequent operations load the most recent
683
696
        data from the database.   This behavior can be disabled using
684
 
        the ``expire_on_commit=False`` option to :func:`.sessionmaker` or
 
697
        the ``expire_on_commit=False`` option to :class:`.sessionmaker` or
685
698
        the :class:`.Session` constructor.
686
699
 
687
700
        If a subtransaction is in effect (which occurs when begin() is called
688
701
        multiple times), the subtransaction will be closed, and the next call
689
702
        to ``commit()`` will operate on the enclosing transaction.
690
703
 
691
 
        For a session configured with autocommit=False, a new transaction will
 
704
        When using the :class:`.Session` in its default mode of
 
705
        ``autocommit=False``, a new transaction will
692
706
        be begun immediately after the commit, but note that the newly begun
693
707
        transaction does *not* use any connection resources until the first
694
708
        SQL is actually emitted.
695
709
 
 
710
        .. seealso::
 
711
 
 
712
            :ref:`session_committing`
 
713
 
696
714
        """
697
715
        if self.transaction is None:
698
716
            if not self.autocommit:
706
724
        """Prepare the current transaction in progress for two phase commit.
707
725
 
708
726
        If no transaction is in progress, this method raises an
709
 
        InvalidRequestError.
 
727
        :exc:`~sqlalchemy.exc.InvalidRequestError`.
710
728
 
711
729
        Only root transactions of two phase sessions can be prepared. If the
712
 
        current transaction is not such, an InvalidRequestError is raised.
 
730
        current transaction is not such, an
 
731
        :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
713
732
 
714
733
        """
715
734
        if self.transaction is None:
728
747
        :class:`.Session` object's transactional state.
729
748
 
730
749
        If this :class:`.Session` is configured with ``autocommit=False``,
731
 
        either the :class:`.Connection` corresponding to the current transaction
732
 
        is returned, or if no transaction is in progress, a new one is begun
733
 
        and the :class:`.Connection` returned (note that no transactional state
734
 
        is established with the DBAPI until the first SQL statement is emitted).
735
 
 
736
 
        Alternatively, if this :class:`.Session` is configured with ``autocommit=True``,
737
 
        an ad-hoc :class:`.Connection` is returned using :meth:`.Engine.contextual_connect`
738
 
        on the underlying :class:`.Engine`.
739
 
 
740
 
        Ambiguity in multi-bind or unbound :class:`.Session` objects can be resolved through
741
 
        any of the optional keyword arguments.   This ultimately makes usage of the
742
 
        :meth:`.get_bind` method for resolution.
 
750
        either the :class:`.Connection` corresponding to the current
 
751
        transaction is returned, or if no transaction is in progress, a new
 
752
        one is begun and the :class:`.Connection` returned (note that no
 
753
        transactional state is established with the DBAPI until the first
 
754
        SQL statement is emitted).
 
755
 
 
756
        Alternatively, if this :class:`.Session` is configured with
 
757
        ``autocommit=True``, an ad-hoc :class:`.Connection` is returned
 
758
        using :meth:`.Engine.contextual_connect` on the underlying
 
759
        :class:`.Engine`.
 
760
 
 
761
        Ambiguity in multi-bind or unbound :class:`.Session` objects can be
 
762
        resolved through any of the optional keyword arguments.   This
 
763
        ultimately makes usage of the :meth:`.get_bind` method for resolution.
743
764
 
744
765
        :param bind:
745
766
          Optional :class:`.Engine` to be used as the bind.  If
759
780
            cannot otherwise be identified.
760
781
 
761
782
        :param close_with_result: Passed to :meth:`Engine.connect`, indicating
762
 
          the :class:`.Connection` should be considered "single use", automatically
763
 
          closing when the first result set is closed.  This flag only has
764
 
          an effect if this :class:`.Session` is configured with ``autocommit=True``
765
 
          and does not already have a  transaction in progress.
 
783
          the :class:`.Connection` should be considered "single use",
 
784
          automatically closing when the first result set is closed.  This
 
785
          flag only has an effect if this :class:`.Session` is configured with
 
786
          ``autocommit=True`` and does not already have a  transaction
 
787
          in progress.
766
788
 
767
789
        :param \**kw:
768
790
          Additional keyword arguments are sent to :meth:`get_bind()`,
804
826
        :func:`~.sql.expression.delete`, and
805
827
        :func:`~.sql.expression.text`.  Plain SQL strings can be passed
806
828
        as well, which in the case of :meth:`.Session.execute` only
807
 
        will be interpreted the same as if it were passed via a :func:`~.expression.text`
808
 
        construct.  That is, the following usage::
 
829
        will be interpreted the same as if it were passed via a
 
830
        :func:`~.expression.text` construct.  That is, the following usage::
809
831
 
810
832
            result = session.execute(
811
833
                        "SELECT * FROM user WHERE id=:param",
821
843
                    )
822
844
 
823
845
        The second positional argument to :meth:`.Session.execute` is an
824
 
        optional parameter set.  Similar to that of :meth:`.Connection.execute`, whether this
825
 
        is passed as a single dictionary, or a list of dictionaries, determines
826
 
        whether the DBAPI cursor's ``execute()`` or ``executemany()`` is used to execute the
 
846
        optional parameter set.  Similar to that of
 
847
        :meth:`.Connection.execute`, whether this is passed as a single
 
848
        dictionary, or a list of dictionaries, determines whether the DBAPI
 
849
        cursor's ``execute()`` or ``executemany()`` is used to execute the
827
850
        statement.   An INSERT construct may be invoked for a single row::
828
851
 
829
852
            result = session.execute(users.insert(), {"id": 7, "name": "somename"})
852
875
        The :class:`.ResultProxy` returned by the :meth:`.Session.execute`
853
876
        method is returned with the "close_with_result" flag set to true;
854
877
        the significance of this flag is that if this :class:`.Session` is
855
 
        autocommitting and does not have a transaction-dedicated :class:`.Connection`
856
 
        available, a temporary :class:`.Connection` is established for the
857
 
        statement execution, which is closed (meaning, returned to the connection
858
 
        pool) when the :class:`.ResultProxy` has consumed all available data.
859
 
        This applies *only* when the :class:`.Session` is configured with
860
 
        autocommit=True and no transaction has been started.
 
878
        autocommitting and does not have a transaction-dedicated
 
879
        :class:`.Connection` available, a temporary :class:`.Connection` is
 
880
        established for the statement execution, which is closed (meaning,
 
881
        returned to the connection pool) when the :class:`.ResultProxy` has
 
882
        consumed all available data. This applies *only* when the
 
883
        :class:`.Session` is configured with autocommit=True and no
 
884
        transaction has been started.
861
885
 
862
886
        :param clause:
863
887
            An executable statement (i.e. an :class:`.Executable` expression
912
936
    def scalar(self, clause, params=None, mapper=None, bind=None, **kw):
913
937
        """Like :meth:`~.Session.execute` but return a scalar result."""
914
938
 
915
 
        return self.execute(clause, params=params, mapper=mapper, bind=bind, **kw).scalar()
 
939
        return self.execute(
 
940
            clause, params=params, mapper=mapper, bind=bind, **kw).scalar()
916
941
 
917
942
    def close(self):
918
943
        """Close this Session.
929
954
            for transaction in self.transaction._iterate_parents():
930
955
                transaction.close()
931
956
 
932
 
    @classmethod
933
 
    def close_all(cls):
934
 
        """Close *all* sessions in memory."""
935
 
 
936
 
        for sess in _sessions.values():
937
 
            sess.close()
938
 
 
939
957
    def expunge_all(self):
940
958
        """Remove all object instances from this ``Session``.
941
959
 
944
962
 
945
963
        """
946
964
        for state in self.identity_map.all_states() + list(self._new):
947
 
            state.detach()
 
965
            state._detach()
948
966
 
949
967
        self.identity_map = self._identity_cls()
950
968
        self._new = {}
951
969
        self._deleted = {}
952
970
 
953
971
    # TODO: need much more test coverage for bind_mapper() and similar !
954
 
    # TODO: + crystalize + document resolution order vis. bind_mapper/bind_table
 
972
    # TODO: + crystalize + document resolution order
 
973
    #       vis. bind_mapper/bind_table
955
974
 
956
975
    def bind_mapper(self, mapper, bind):
957
976
        """Bind operations for a mapper to a Connectable.
967
986
 
968
987
        """
969
988
        if isinstance(mapper, type):
970
 
            mapper = _class_mapper(mapper)
 
989
            mapper = class_mapper(mapper)
971
990
 
972
991
        self.__binds[mapper.base_mapper] = bind
973
992
        for t in mapper._all_tables:
1020
1039
           linked to the :class:`.MetaData` ultimately
1021
1040
           associated with the :class:`.Table` or other
1022
1041
           selectable to which the mapper is mapped.
1023
 
        6. No bind can be found, :class:`.UnboundExecutionError`
 
1042
        6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
1024
1043
           is raised.
1025
1044
 
1026
1045
        :param mapper:
1034
1053
        :param clause:
1035
1054
            A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
1036
1055
            :func:`~.sql.expression.text`,
1037
 
            etc.).  If the ``mapper`` argument is not present or could not produce
1038
 
            a bind, the given expression construct will be searched for a bound
1039
 
            element, typically a :class:`.Table` associated with bound
1040
 
            :class:`.MetaData`.
 
1056
            etc.).  If the ``mapper`` argument is not present or could not
 
1057
            produce a bind, the given expression construct will be searched
 
1058
            for a bound element, typically a :class:`.Table` associated with
 
1059
            bound :class:`.MetaData`.
1041
1060
 
1042
1061
        """
1043
1062
        if mapper is clause is None:
1119
1138
        if self.autoflush and not self._flushing:
1120
1139
            self.flush()
1121
1140
 
1122
 
    def _finalize_loaded(self, states):
1123
 
        for state, dict_ in states.items():
1124
 
            state.commit_all(dict_, self.identity_map)
1125
 
 
1126
1141
    def refresh(self, instance, attribute_names=None, lockmode=None):
1127
1142
        """Expire and refresh the attributes on the given instance.
1128
1143
 
1158
1173
 
1159
1174
        self._expire_state(state, attribute_names)
1160
1175
 
1161
 
        if self.query(_object_mapper(instance))._load_on_ident(
 
1176
        if loading.load_on_ident(
 
1177
                self.query(object_mapper(instance)),
1162
1178
                state.key, refresh_state=state,
1163
1179
                lockmode=lockmode,
1164
1180
                only_load_props=attribute_names) is None:
1165
1181
            raise sa_exc.InvalidRequestError(
1166
1182
                "Could not refresh instance '%s'" %
1167
 
                mapperutil.instance_str(instance))
 
1183
                orm_util.instance_str(instance))
1168
1184
 
1169
1185
    def expire_all(self):
1170
1186
        """Expires all persistent instances within this Session.
1189
1205
 
1190
1206
        """
1191
1207
        for state in self.identity_map.all_states():
1192
 
            state.expire(state.dict, self.identity_map._modified)
 
1208
            state._expire(state.dict, self.identity_map._modified)
1193
1209
 
1194
1210
    def expire(self, instance, attribute_names=None):
1195
1211
        """Expire the attributes on an instance.
1227
1243
    def _expire_state(self, state, attribute_names):
1228
1244
        self._validate_persistent(state)
1229
1245
        if attribute_names:
1230
 
            state.expire_attributes(state.dict, attribute_names)
 
1246
            state._expire_attributes(state.dict, attribute_names)
1231
1247
        else:
1232
1248
            # pre-fetch the full cascade since the expire is going to
1233
1249
            # remove associations
1241
1257
        """Expire a state if persistent, else expunge if pending"""
1242
1258
 
1243
1259
        if state.key:
1244
 
            state.expire(state.dict, self.identity_map._modified)
 
1260
            state._expire(state.dict, self.identity_map._modified)
1245
1261
        elif state in self._new:
1246
1262
            self._new.pop(state)
1247
 
            state.detach()
 
1263
            state._detach()
1248
1264
 
1249
1265
    @util.deprecated("0.7", "The non-weak-referencing identity map "
1250
1266
                        "feature is no longer needed.")
1275
1291
        if state.session_id is not self.hash_key:
1276
1292
            raise sa_exc.InvalidRequestError(
1277
1293
                "Instance %s is not present in this Session" %
1278
 
                mapperutil.state_str(state))
 
1294
                orm_util.state_str(state))
1279
1295
 
1280
1296
        cascaded = list(state.manager.mapper.cascade_iterator(
1281
1297
                                    'expunge', state))
1286
1302
    def _expunge_state(self, state):
1287
1303
        if state in self._new:
1288
1304
            self._new.pop(state)
1289
 
            state.detach()
 
1305
            state._detach()
1290
1306
        elif self.identity_map.contains_state(state):
1291
1307
            self.identity_map.discard(state)
1292
1308
            self._deleted.pop(state, None)
1293
 
            state.detach()
 
1309
            state._detach()
1294
1310
        elif self.transaction:
1295
1311
            self.transaction._deleted.pop(state, None)
1296
1312
 
1297
 
    def _register_newly_persistent(self, state):
1298
 
        mapper = _state_mapper(state)
1299
 
 
1300
 
        # prevent against last minute dereferences of the object
1301
 
        obj = state.obj()
1302
 
        if obj is not None:
1303
 
 
1304
 
            instance_key = mapper._identity_key_from_state(state)
1305
 
 
1306
 
            if _none_set.issubset(instance_key[1]) and \
1307
 
                not mapper.allow_partial_pks or \
1308
 
                _none_set.issuperset(instance_key[1]):
1309
 
                raise exc.FlushError(
1310
 
                    "Instance %s has a NULL identity key.  If this is an "
1311
 
                    "auto-generated value, check that the database table "
1312
 
                    "allows generation of new primary key values, and that "
1313
 
                    "the mapped Column object is configured to expect these "
1314
 
                    "generated values.  Ensure also that this flush() is "
1315
 
                    "not occurring at an inappropriate time, such as within "
1316
 
                    "a load() event." % mapperutil.state_str(state)
1317
 
                )
1318
 
 
1319
 
            if state.key is None:
1320
 
                state.key = instance_key
1321
 
            elif state.key != instance_key:
1322
 
                # primary key switch. use discard() in case another
1323
 
                # state has already replaced this one in the identity
1324
 
                # map (see test/orm/test_naturalpks.py ReversePKsTest)
1325
 
                self.identity_map.discard(state)
1326
 
                state.key = instance_key
1327
 
 
1328
 
            self.identity_map.replace(state)
1329
 
            state.commit_all(state.dict, self.identity_map)
1330
 
 
 
1313
    def _register_newly_persistent(self, states):
 
1314
        for state in states:
 
1315
            mapper = _state_mapper(state)
 
1316
 
 
1317
            # prevent against last minute dereferences of the object
 
1318
            obj = state.obj()
 
1319
            if obj is not None:
 
1320
 
 
1321
                instance_key = mapper._identity_key_from_state(state)
 
1322
 
 
1323
                if _none_set.issubset(instance_key[1]) and \
 
1324
                    not mapper.allow_partial_pks or \
 
1325
                    _none_set.issuperset(instance_key[1]):
 
1326
                    raise exc.FlushError(
 
1327
                        "Instance %s has a NULL identity key.  If this is an "
 
1328
                        "auto-generated value, check that the database table "
 
1329
                        "allows generation of new primary key values, and "
 
1330
                        "that the mapped Column object is configured to "
 
1331
                        "expect these generated values.  Ensure also that "
 
1332
                        "this flush() is not occurring at an inappropriate "
 
1333
                        "time, such aswithin a load() event."
 
1334
                        % orm_util.state_str(state)
 
1335
                    )
 
1336
 
 
1337
                if state.key is None:
 
1338
                    state.key = instance_key
 
1339
                elif state.key != instance_key:
 
1340
                    # primary key switch. use discard() in case another
 
1341
                    # state has already replaced this one in the identity
 
1342
                    # map (see test/orm/test_naturalpks.py ReversePKsTest)
 
1343
                    self.identity_map.discard(state)
 
1344
                    if state in self.transaction._key_switches:
 
1345
                        orig_key = self.transaction._key_switches[state][0]
 
1346
                    else:
 
1347
                        orig_key = state.key
 
1348
                    self.transaction._key_switches[state] = (
 
1349
                        orig_key, instance_key)
 
1350
                    state.key = instance_key
 
1351
 
 
1352
                self.identity_map.replace(state)
 
1353
 
 
1354
        statelib.InstanceState._commit_all_states(
 
1355
            ((state, state.dict) for state in states),
 
1356
            self.identity_map
 
1357
        )
 
1358
 
 
1359
        self._register_altered(states)
1331
1360
        # remove from new last, might be the last strong ref
1332
 
        if state in self._new:
 
1361
        for state in set(states).intersection(self._new):
 
1362
            self._new.pop(state)
 
1363
 
 
1364
    def _register_altered(self, states):
 
1365
        if self._enable_transaction_accounting and self.transaction:
 
1366
            for state in states:
 
1367
                if state in self._new:
 
1368
                    self.transaction._new[state] = True
 
1369
                else:
 
1370
                    self.transaction._dirty[state] = True
 
1371
 
 
1372
    def _remove_newly_deleted(self, states):
 
1373
        for state in states:
1333
1374
            if self._enable_transaction_accounting and self.transaction:
1334
 
                self.transaction._new[state] = True
1335
 
            self._new.pop(state)
1336
 
 
1337
 
    def _remove_newly_deleted(self, state):
1338
 
        if self._enable_transaction_accounting and self.transaction:
1339
 
            self.transaction._deleted[state] = True
1340
 
 
1341
 
        self.identity_map.discard(state)
1342
 
        self._deleted.pop(state, None)
1343
 
        state.deleted = True
1344
 
 
1345
 
    def add(self, instance):
 
1375
                self.transaction._deleted[state] = True
 
1376
 
 
1377
            self.identity_map.discard(state)
 
1378
            self._deleted.pop(state, None)
 
1379
            state.deleted = True
 
1380
 
 
1381
    def add(self, instance, _warn=True):
1346
1382
        """Place an object in the ``Session``.
1347
1383
 
1348
1384
        Its state will be persisted to the database on the next flush
1352
1388
        is ``expunge()``.
1353
1389
 
1354
1390
        """
 
1391
        if _warn and self._warn_on_events:
 
1392
            self._flush_warning("Session.add()")
 
1393
 
1355
1394
        try:
1356
1395
            state = attributes.instance_state(instance)
1357
1396
        except exc.NO_STATE:
1362
1401
    def add_all(self, instances):
1363
1402
        """Add the given collection of instances to this ``Session``."""
1364
1403
 
 
1404
        if self._warn_on_events:
 
1405
            self._flush_warning("Session.add_all()")
 
1406
 
1365
1407
        for instance in instances:
1366
 
            self.add(instance)
 
1408
            self.add(instance, _warn=False)
1367
1409
 
1368
1410
    def _save_or_update_state(self, state):
1369
1411
        self._save_or_update_impl(state)
1381
1423
        The database delete operation occurs upon ``flush()``.
1382
1424
 
1383
1425
        """
 
1426
        if self._warn_on_events:
 
1427
            self._flush_warning("Session.delete()")
 
1428
 
1384
1429
        try:
1385
1430
            state = attributes.instance_state(instance)
1386
1431
        except exc.NO_STATE:
1389
1434
        if state.key is None:
1390
1435
            raise sa_exc.InvalidRequestError(
1391
1436
                "Instance '%s' is not persisted" %
1392
 
                mapperutil.state_str(state))
 
1437
                orm_util.state_str(state))
1393
1438
 
1394
1439
        if state in self._deleted:
1395
1440
            return
1397
1442
        # ensure object is attached to allow the
1398
1443
        # cascade operation to load deferred attributes
1399
1444
        # and collections
1400
 
        self._attach(state)
 
1445
        self._attach(state, include_before=True)
1401
1446
 
1402
1447
        # grab the cascades before adding the item to the deleted list
1403
1448
        # so that autoflush does not delete the item
1411
1456
        for o, m, st_, dct_ in cascade_states:
1412
1457
            self._delete_impl(st_)
1413
1458
 
1414
 
    def merge(self, instance, load=True, **kw):
 
1459
    def merge(self, instance, load=True):
1415
1460
        """Copy the state of a given instance into a corresponding instance
1416
1461
        within this :class:`.Session`.
1417
1462
 
1419
1464
        source instance, and attempts to reconcile it with an instance of the
1420
1465
        same primary key in the session.   If not found locally, it attempts
1421
1466
        to load the object from the database based on primary key, and if
1422
 
        none can be located, creates a new instance.  The state of each attribute
1423
 
        on the source instance is then copied to the target instance.
 
1467
        none can be located, creates a new instance.  The state of each
 
1468
        attribute on the source instance is then copied to the target instance.
1424
1469
        The resulting target instance is then returned by the method; the
1425
1470
        original source instance is left unmodified, and un-associated with the
1426
1471
        :class:`.Session` if not already.
1454
1499
         should be "clean" as well, else this suggests a mis-use of the method.
1455
1500
 
1456
1501
        """
1457
 
        if 'dont_load' in kw:
1458
 
            load = not kw['dont_load']
1459
 
            util.warn_deprecated('dont_load=True has been renamed to '
1460
 
                                 'load=False.')
 
1502
 
 
1503
        if self._warn_on_events:
 
1504
            self._flush_warning("Session.merge()")
1461
1505
 
1462
1506
        _recursive = {}
1463
1507
 
1465
1509
            # flush current contents if we expect to load data
1466
1510
            self._autoflush()
1467
1511
 
1468
 
        _object_mapper(instance) # verify mapped
 
1512
        object_mapper(instance)  # verify mapped
1469
1513
        autoflush = self.autoflush
1470
1514
        try:
1471
1515
            self.autoflush = False
1554
1598
                            "merging to update the most recent version."
1555
1599
                            % (
1556
1600
                                existing_version,
1557
 
                                mapperutil.state_str(merged_state),
 
1601
                                orm_util.state_str(merged_state),
1558
1602
                                merged_version
1559
1603
                            ))
1560
1604
 
1568
1612
 
1569
1613
        if not load:
1570
1614
            # remove any history
1571
 
            merged_state.commit_all(merged_dict, self.identity_map)
 
1615
            merged_state._commit_all(merged_dict, self.identity_map)
1572
1616
 
1573
1617
        if new_instance:
1574
1618
            merged_state.manager.dispatch.load(merged_state, None)
1575
1619
        return merged
1576
1620
 
1577
 
    @classmethod
1578
 
    def identity_key(cls, *args, **kwargs):
1579
 
        return mapperutil.identity_key(*args, **kwargs)
1580
 
 
1581
 
    @classmethod
1582
 
    def object_session(cls, instance):
1583
 
        """Return the ``Session`` to which an object belongs."""
1584
 
 
1585
 
        return object_session(instance)
1586
 
 
1587
1621
    def _validate_persistent(self, state):
1588
1622
        if not self.identity_map.contains_state(state):
1589
1623
            raise sa_exc.InvalidRequestError(
1590
1624
                "Instance '%s' is not persistent within this Session" %
1591
 
                mapperutil.state_str(state))
 
1625
                orm_util.state_str(state))
1592
1626
 
1593
1627
    def _save_impl(self, state):
1594
1628
        if state.key is not None:
1595
1629
            raise sa_exc.InvalidRequestError(
1596
1630
                "Object '%s' already has an identity - it can't be registered "
1597
 
                "as pending" % mapperutil.state_str(state))
 
1631
                "as pending" % orm_util.state_str(state))
1598
1632
 
1599
 
        self._attach(state)
 
1633
        self._before_attach(state)
1600
1634
        if state not in self._new:
1601
1635
            self._new[state] = state.obj()
1602
1636
            state.insert_order = len(self._new)
 
1637
        self._attach(state)
1603
1638
 
1604
 
    def _update_impl(self, state):
 
1639
    def _update_impl(self, state, discard_existing=False):
1605
1640
        if (self.identity_map.contains_state(state) and
1606
1641
            state not in self._deleted):
1607
1642
            return
1609
1644
        if state.key is None:
1610
1645
            raise sa_exc.InvalidRequestError(
1611
1646
                "Instance '%s' is not persisted" %
1612
 
                mapperutil.state_str(state))
 
1647
                orm_util.state_str(state))
1613
1648
 
1614
1649
        if state.deleted:
1615
1650
            raise sa_exc.InvalidRequestError(
1616
1651
                "Instance '%s' has been deleted.  Use the make_transient() "
1617
1652
                "function to send this object back to the transient state." %
1618
 
                mapperutil.state_str(state)
 
1653
                orm_util.state_str(state)
1619
1654
            )
 
1655
        self._before_attach(state)
 
1656
        self._deleted.pop(state, None)
 
1657
        if discard_existing:
 
1658
            self.identity_map.replace(state)
 
1659
        else:
 
1660
            self.identity_map.add(state)
1620
1661
        self._attach(state)
1621
 
        self._deleted.pop(state, None)
1622
 
        self.identity_map.add(state)
1623
1662
 
1624
1663
    def _save_or_update_impl(self, state):
1625
1664
        if state.key is None:
1634
1673
        if state.key is None:
1635
1674
            return
1636
1675
 
1637
 
        self._attach(state)
 
1676
        self._attach(state, include_before=True)
1638
1677
        self._deleted[state] = state.obj()
1639
1678
        self.identity_map.add(state)
1640
1679
 
1641
 
    def _attach(self, state):
 
1680
    def enable_relationship_loading(self, obj):
 
1681
        """Associate an object with this :class:`.Session` for related
 
1682
        object loading.
 
1683
 
 
1684
        .. warning::
 
1685
 
 
1686
            :meth:`.enable_relationship_loading` exists to serve special
 
1687
            use cases and is not recommended for general use.
 
1688
 
 
1689
        Accesses of attributes mapped with :func:`.relationship`
 
1690
        will attempt to load a value from the database using this
 
1691
        :class:`.Session` as the source of connectivity.  The values
 
1692
        will be loaded based on foreign key values present on this
 
1693
        object - it follows that this functionality
 
1694
        generally only works for many-to-one-relationships.
 
1695
 
 
1696
        The object will be attached to this session, but will
 
1697
        **not** participate in any persistence operations; its state
 
1698
        for almost all purposes will remain either "transient" or
 
1699
        "detached", except for the case of relationship loading.
 
1700
 
 
1701
        Also note that backrefs will often not work as expected.
 
1702
        Altering a relationship-bound attribute on the target object
 
1703
        may not fire off a backref event, if the effective value
 
1704
        is what was already loaded from a foreign-key-holding value.
 
1705
 
 
1706
        The :meth:`.Session.enable_relationship_loading` method supersedes
 
1707
        the ``load_on_pending`` flag on :func:`.relationship`.   Unlike
 
1708
        that flag, :meth:`.Session.enable_relationship_loading` allows
 
1709
        an object to remain transient while still being able to load
 
1710
        related items.
 
1711
 
 
1712
        To make a transient object associated with a :class:`.Session`
 
1713
        via :meth:`.Session.enable_relationship_loading` pending, add
 
1714
        it to the :class:`.Session` using :meth:`.Session.add` normally.
 
1715
 
 
1716
        :meth:`.Session.enable_relationship_loading` does not improve
 
1717
        behavior when the ORM is used normally - object references should be
 
1718
        constructed at the object level, not at the foreign key level, so
 
1719
        that they are present in an ordinary way before flush()
 
1720
        proceeds.  This method is not intended for general use.
 
1721
 
 
1722
        .. versionadded:: 0.8
 
1723
 
 
1724
        """
 
1725
        state = attributes.instance_state(obj)
 
1726
        self._attach(state, include_before=True)
 
1727
        state._load_pending = True
 
1728
 
 
1729
    def _before_attach(self, state):
 
1730
        if state.session_id != self.hash_key and \
 
1731
                self.dispatch.before_attach:
 
1732
            self.dispatch.before_attach(self, state.obj())
 
1733
 
 
1734
    def _attach(self, state, include_before=False):
1642
1735
        if state.key and \
1643
1736
            state.key in self.identity_map and \
1644
 
            not self.identity_map.contains_state(state):
 
1737
                not self.identity_map.contains_state(state):
1645
1738
            raise sa_exc.InvalidRequestError("Can't attach instance "
1646
1739
                    "%s; another instance with key %s is already "
1647
1740
                    "present in this session."
1648
 
                    % (mapperutil.state_str(state), state.key))
 
1741
                    % (orm_util.state_str(state), state.key))
1649
1742
 
1650
1743
        if state.session_id and \
1651
1744
                state.session_id is not self.hash_key and \
1652
1745
                state.session_id in _sessions:
1653
1746
            raise sa_exc.InvalidRequestError(
1654
1747
                "Object '%s' is already attached to session '%s' "
1655
 
                "(this is '%s')" % (mapperutil.state_str(state),
 
1748
                "(this is '%s')" % (orm_util.state_str(state),
1656
1749
                                    state.session_id, self.hash_key))
1657
1750
 
1658
1751
        if state.session_id != self.hash_key:
 
1752
            if include_before and \
 
1753
                    self.dispatch.before_attach:
 
1754
                self.dispatch.before_attach(self, state.obj())
1659
1755
            state.session_id = self.hash_key
 
1756
            if state.modified and state._strong_obj is None:
 
1757
                state._strong_obj = state.obj()
1660
1758
            if self.dispatch.after_attach:
1661
1759
                self.dispatch.after_attach(self, state.obj())
1662
1760
 
1674
1772
        return self._contains_state(state)
1675
1773
 
1676
1774
    def __iter__(self):
1677
 
        """Iterate over all pending or persistent instances within this Session."""
 
1775
        """Iterate over all pending or persistent instances within this
 
1776
        Session.
1678
1777
 
 
1778
        """
1679
1779
        return iter(list(self._new.values()) + self.identity_map.values())
1680
1780
 
1681
1781
    def _contains_state(self, state):
1719
1819
        finally:
1720
1820
            self._flushing = False
1721
1821
 
 
1822
    def _flush_warning(self, method):
 
1823
        util.warn(
 
1824
            "Usage of the '%s' operation is not currently supported "
 
1825
            "within the execution stage of the flush process. "
 
1826
            "Results may not be consistent.  Consider using alternative "
 
1827
            "event listeners or connection-level operations instead."
 
1828
            % method)
 
1829
 
1722
1830
    def _is_clean(self):
1723
1831
        return not self.identity_map.check_modified() and \
1724
1832
                not self._deleted and \
1768
1876
            proc = new.union(dirty).difference(deleted)
1769
1877
 
1770
1878
        for state in proc:
1771
 
            is_orphan = _state_mapper(state)._is_orphan(state) and state.has_identity
 
1879
            is_orphan = (
 
1880
                _state_mapper(state)._is_orphan(state) and state.has_identity)
1772
1881
            flush_context.register_object(state, isdelete=is_orphan)
1773
1882
            processed.add(state)
1774
1883
 
1786
1895
        flush_context.transaction = transaction = self.begin(
1787
1896
            subtransactions=True)
1788
1897
        try:
1789
 
            flush_context.execute()
 
1898
            self._warn_on_events = True
 
1899
            try:
 
1900
                flush_context.execute()
 
1901
            finally:
 
1902
                self._warn_on_events = False
1790
1903
 
1791
1904
            self.dispatch.after_flush(self, flush_context)
1792
1905
 
1793
1906
            flush_context.finalize_flush_changes()
1794
1907
 
 
1908
            if not objects and self.identity_map._modified:
 
1909
                len_ = len(self.identity_map._modified)
 
1910
 
 
1911
                statelib.InstanceState._commit_all_states(
 
1912
                                [(state, state.dict) for state in
 
1913
                                        self.identity_map._modified],
 
1914
                                instance_dict=self.identity_map)
 
1915
                util.warn("Attribute history events accumulated on %d "
 
1916
                        "previously clean instances "
 
1917
                        "within inner-flush event handlers have been reset, "
 
1918
                        "and will not result in database updates. "
 
1919
                        "Consider using set_committed_value() within "
 
1920
                        "inner-flush event handlers to avoid this warning."
 
1921
                                    % len_)
 
1922
 
1795
1923
            # useful assertions:
1796
1924
            #if not objects:
1797
1925
            #    assert not self.identity_map._modified
1804
1932
            transaction.commit()
1805
1933
 
1806
1934
        except:
1807
 
            transaction.rollback(_capture_exception=True)
1808
 
            raise
1809
 
 
 
1935
            with util.safe_reraise():
 
1936
                transaction.rollback(_capture_exception=True)
1810
1937
 
1811
1938
    def is_modified(self, instance, include_collections=True,
1812
 
                            passive=attributes.PASSIVE_OFF):
 
1939
                            passive=True):
1813
1940
        """Return ``True`` if the given instance has locally
1814
1941
        modified attributes.
1815
1942
 
1824
1951
 
1825
1952
        E.g.::
1826
1953
 
1827
 
            return session.is_modified(someobject, passive=True)
 
1954
            return session.is_modified(someobject)
1828
1955
 
1829
1956
        .. versionchanged:: 0.8
1830
 
            In SQLAlchemy 0.7 and earlier, the ``passive``
1831
 
            flag should **always** be explicitly set to ``True``.
1832
 
            The current default value of :data:`.attributes.PASSIVE_OFF`
1833
 
            for this flag is incorrect, in that it loads unloaded
1834
 
            collections and attributes which by definition
1835
 
            have no modified state, and furthermore trips off
1836
 
            autoflush which then causes all subsequent, possibly
1837
 
            modified attributes to lose their modified state.
1838
 
            The default value of the flag will be changed in 0.8.
 
1957
            When using SQLAlchemy 0.7 and earlier, the ``passive``
 
1958
            flag should **always** be explicitly set to ``True``,
 
1959
            else SQL loads/autoflushes may proceed which can affect
 
1960
            the modified state itself:
 
1961
            ``session.is_modified(someobject, passive=True)``\ .
 
1962
            In 0.8 and above, the behavior is corrected and
 
1963
            this flag is ignored.
1839
1964
 
1840
1965
        A few caveats to this method apply:
1841
1966
 
1856
1981
          usually needed, and in those few cases where it isn't, is less
1857
1982
          expensive on average than issuing a defensive SELECT.
1858
1983
 
1859
 
          The "old" value is fetched unconditionally only if the attribute
1860
 
          container has the ``active_history`` flag set to ``True``. This flag
1861
 
          is set typically for primary key attributes and scalar object references
1862
 
          that are not a simple many-to-one.  To set this flag for
1863
 
          any arbitrary mapped column, use the ``active_history`` argument
1864
 
          with :func:`.column_property`.
 
1984
          The "old" value is fetched unconditionally upon set only if the
 
1985
          attribute container has the ``active_history`` flag set to ``True``.
 
1986
          This flag is set typically for primary key attributes and scalar
 
1987
          object references that are not a simple many-to-one.  To set this
 
1988
          flag for any arbitrary mapped column, use the ``active_history``
 
1989
          argument with :func:`.column_property`.
1865
1990
 
1866
1991
        :param instance: mapped instance to be tested for pending changes.
1867
 
        :param include_collections: Indicates if multivalued collections should be
1868
 
         included in the operation.  Setting this to ``False`` is a way to detect
1869
 
         only local-column based properties (i.e. scalar columns or many-to-one
1870
 
         foreign keys) that would result in an UPDATE for this instance upon
1871
 
         flush.
1872
 
        :param passive: Indicates if unloaded attributes and
1873
 
         collections should be loaded in the course of performing
1874
 
         this test.  If set to ``False``, or left at its default
1875
 
         value of :data:`.PASSIVE_OFF`, unloaded attributes
1876
 
         will be loaded.  If set to ``True`` or
1877
 
         :data:`.PASSIVE_NO_INITIALIZE`, unloaded
1878
 
         collections and attributes will remain unloaded.  As
1879
 
         noted previously, the existence of this flag here
1880
 
         is a bug, as unloaded attributes by definition have
1881
 
         no changes, and the load operation also triggers an
1882
 
         autoflush which then cancels out subsequent changes.
1883
 
         This flag should **always be set to True**.
1884
 
 
 
1992
        :param include_collections: Indicates if multivalued collections
 
1993
         should be included in the operation.  Setting this to ``False`` is a
 
1994
         way to detect only local-column based properties (i.e. scalar columns
 
1995
         or many-to-one foreign keys) that would result in an UPDATE for this
 
1996
         instance upon flush.
 
1997
        :param passive:
1885
1998
         .. versionchanged:: 0.8
1886
 
             The flag will be deprecated and the default
1887
 
             set to ``True``.
 
1999
             Ignored for backwards compatibility.
 
2000
             When using SQLAlchemy 0.7 and earlier, this flag should always
 
2001
             be set to ``True``.
1888
2002
 
1889
2003
        """
1890
 
        try:
1891
 
            state = attributes.instance_state(instance)
1892
 
        except exc.NO_STATE:
1893
 
            raise exc.UnmappedInstanceError(instance)
 
2004
        state = object_state(instance)
 
2005
 
 
2006
        if not state.modified:
 
2007
            return False
 
2008
 
1894
2009
        dict_ = state.dict
1895
2010
 
1896
 
        if passive is True:
1897
 
            passive = attributes.PASSIVE_NO_INITIALIZE
1898
 
        elif passive is False:
1899
 
            passive = attributes.PASSIVE_OFF
1900
 
 
1901
2011
        for attr in state.manager.attributes:
1902
2012
            if \
1903
2013
                (
1907
2017
                continue
1908
2018
 
1909
2019
            (added, unchanged, deleted) = \
1910
 
                    attr.impl.get_history(state, dict_, passive=passive)
 
2020
                    attr.impl.get_history(state, dict_,
 
2021
                            passive=attributes.NO_CHANGE)
1911
2022
 
1912
2023
            if added or deleted:
1913
2024
                return True
1914
 
        return False
 
2025
        else:
 
2026
            return False
1915
2027
 
1916
2028
    @property
1917
2029
    def is_active(self):
1937
2049
        target :class:`.Connection` to a user-defined event listener.
1938
2050
 
1939
2051
        The "partial rollback" state refers to when an "inner" transaction,
1940
 
        typically used during a flush, encounters an error and emits
1941
 
        a rollback of the DBAPI connection.  At this point, the :class:`.Session`
1942
 
        is in "partial rollback" and awaits for the user to call :meth:`.rollback`,
1943
 
        in order to close out the transaction stack.  It is in this "partial
1944
 
        rollback" period that the :attr:`.is_active` flag returns False.  After
1945
 
        the call to :meth:`.rollback`, the :class:`.SessionTransaction` is replaced
 
2052
        typically used during a flush, encounters an error and emits a
 
2053
        rollback of the DBAPI connection.  At this point, the
 
2054
        :class:`.Session` is in "partial rollback" and awaits for the user to
 
2055
        call :meth:`.Session.rollback`, in order to close out the
 
2056
        transaction stack.  It is in this "partial rollback" period that the
 
2057
        :attr:`.is_active` flag returns False.  After the call to
 
2058
        :meth:`.Session.rollback`, the :class:`.SessionTransaction` is replaced
1946
2059
        with a new one and :attr:`.is_active` returns ``True`` again.
1947
2060
 
1948
2061
        When a :class:`.Session` is used in ``autocommit=True`` mode, the
1949
2062
        :class:`.SessionTransaction` is only instantiated within the scope
1950
2063
        of a flush call, or when :meth:`.Session.begin` is called.  So
1951
2064
        :attr:`.is_active` will always be ``False`` outside of a flush or
1952
 
        :meth:`.begin` block in this mode, and will be ``True`` within the
1953
 
        :meth:`.begin` block as long as it doesn't enter "partial rollback"
1954
 
        state.
 
2065
        :meth:`.Session.begin` block in this mode, and will be ``True``
 
2066
        within the :meth:`.Session.begin` block as long as it doesn't enter
 
2067
        "partial rollback" state.
1955
2068
 
1956
2069
        From all the above, it follows that the only purpose to this flag is
1957
2070
        for application frameworks that wish to detect is a "rollback" is
1958
 
        necessary within a generic error handling routine, for :class:`.Session`
1959
 
        objects that would otherwise be in "partial rollback" mode.  In
1960
 
        a typical integration case, this is also not necessary as it is standard
1961
 
        practice to emit :meth:`.Session.rollback` unconditionally within the
1962
 
        outermost exception catch.
 
2071
        necessary within a generic error handling routine, for
 
2072
        :class:`.Session` objects that would otherwise be in
 
2073
        "partial rollback" mode.  In a typical integration case, this is also
 
2074
        not necessary as it is standard practice to emit
 
2075
        :meth:`.Session.rollback` unconditionally within the outermost
 
2076
        exception catch.
1963
2077
 
1964
2078
        To track the transactional state of a :class:`.Session` fully,
1965
2079
        use event listeners, primarily the :meth:`.SessionEvents.after_begin`,
1966
 
        :meth:`.SessionEvents.after_commit`, :meth:`.SessionEvents.after_rollback`
1967
 
        and related events.
 
2080
        :meth:`.SessionEvents.after_commit`,
 
2081
        :meth:`.SessionEvents.after_rollback` and related events.
1968
2082
 
1969
2083
        """
1970
2084
        return self.transaction and self.transaction.is_active
2033
2147
 
2034
2148
        return util.IdentitySet(self._new.values())
2035
2149
 
 
2150
 
 
2151
class sessionmaker(_SessionClassMethods):
 
2152
    """A configurable :class:`.Session` factory.
 
2153
 
 
2154
    The :class:`.sessionmaker` factory generates new
 
2155
    :class:`.Session` objects when called, creating them given
 
2156
    the configurational arguments established here.
 
2157
 
 
2158
    e.g.::
 
2159
 
 
2160
        # global scope
 
2161
        Session = sessionmaker(autoflush=False)
 
2162
 
 
2163
        # later, in a local scope, create and use a session:
 
2164
        sess = Session()
 
2165
 
 
2166
    Any keyword arguments sent to the constructor itself will override the
 
2167
    "configured" keywords::
 
2168
 
 
2169
        Session = sessionmaker()
 
2170
 
 
2171
        # bind an individual session to a connection
 
2172
        sess = Session(bind=connection)
 
2173
 
 
2174
    The class also includes a method :meth:`.configure`, which can
 
2175
    be used to specify additional keyword arguments to the factory, which
 
2176
    will take effect for subsequent :class:`.Session` objects generated.
 
2177
    This is usually used to associate one or more :class:`.Engine` objects
 
2178
    with an existing :class:`.sessionmaker` factory before it is first
 
2179
    used::
 
2180
 
 
2181
        # application starts
 
2182
        Session = sessionmaker()
 
2183
 
 
2184
        # ... later
 
2185
        engine = create_engine('sqlite:///foo.db')
 
2186
        Session.configure(bind=engine)
 
2187
 
 
2188
        sess = Session()
 
2189
 
 
2190
    .. seealso:
 
2191
 
 
2192
        :ref:`session_getting` - introductory text on creating
 
2193
        sessions using :class:`.sessionmaker`.
 
2194
 
 
2195
    """
 
2196
 
 
2197
    def __init__(self, bind=None, class_=Session, autoflush=True,
 
2198
                        autocommit=False,
 
2199
                        expire_on_commit=True, **kw):
 
2200
        """Construct a new :class:`.sessionmaker`.
 
2201
 
 
2202
        All arguments here except for ``class_`` correspond to arguments
 
2203
        accepted by :class:`.Session` directly.  See the
 
2204
        :meth:`.Session.__init__` docstring for more details on parameters.
 
2205
 
 
2206
        :param bind: a :class:`.Engine` or other :class:`.Connectable` with
 
2207
         which newly created :class:`.Session` objects will be associated.
 
2208
        :param class_: class to use in order to create new :class:`.Session`
 
2209
         objects.  Defaults to :class:`.Session`.
 
2210
        :param autoflush: The autoflush setting to use with newly created
 
2211
         :class:`.Session` objects.
 
2212
        :param autocommit: The autocommit setting to use with newly created
 
2213
         :class:`.Session` objects.
 
2214
        :param expire_on_commit=True: the expire_on_commit setting to use
 
2215
         with newly created :class:`.Session` objects.
 
2216
        :param \**kw: all other keyword arguments are passed to the constructor
 
2217
         of newly created :class:`.Session` objects.
 
2218
 
 
2219
        """
 
2220
        kw['bind'] = bind
 
2221
        kw['autoflush'] = autoflush
 
2222
        kw['autocommit'] = autocommit
 
2223
        kw['expire_on_commit'] = expire_on_commit
 
2224
        self.kw = kw
 
2225
        # make our own subclass of the given class, so that
 
2226
        # events can be associated with it specifically.
 
2227
        self.class_ = type(class_.__name__, (class_,), {})
 
2228
 
 
2229
    def __call__(self, **local_kw):
 
2230
        """Produce a new :class:`.Session` object using the configuration
 
2231
        established in this :class:`.sessionmaker`.
 
2232
 
 
2233
        In Python, the ``__call__`` method is invoked on an object when
 
2234
        it is "called" in the same way as a function::
 
2235
 
 
2236
            Session = sessionmaker()
 
2237
            session = Session()  # invokes sessionmaker.__call__()
 
2238
 
 
2239
        """
 
2240
        for k, v in self.kw.items():
 
2241
            local_kw.setdefault(k, v)
 
2242
        return self.class_(**local_kw)
 
2243
 
 
2244
    def configure(self, **new_kw):
 
2245
        """(Re)configure the arguments for this sessionmaker.
 
2246
 
 
2247
        e.g.::
 
2248
 
 
2249
            Session = sessionmaker()
 
2250
 
 
2251
            Session.configure(bind=create_engine('sqlite://'))
 
2252
        """
 
2253
        self.kw.update(new_kw)
 
2254
 
 
2255
    def __repr__(self):
 
2256
        return "%s(class_=%r%s)" % (
 
2257
                    self.__class__.__name__,
 
2258
                    self.class_.__name__,
 
2259
                    ", ".join("%s=%r" % (k, v) for k, v in self.kw.items())
 
2260
                )
 
2261
 
2036
2262
_sessions = weakref.WeakValueDictionary()
2037
2263
 
 
2264
 
2038
2265
def make_transient(instance):
2039
2266
    """Make the given instance 'transient'.
2040
2267
 
2063
2290
    if state.deleted:
2064
2291
        del state.deleted
2065
2292
 
 
2293
 
2066
2294
def object_session(instance):
2067
2295
    """Return the ``Session`` to which instance belongs.
2068
2296