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
7
import sqlalchemy.exceptions as sa_exc
8
from sqlalchemy.util import ScopedRegistry, ThreadLocalRegistry, \
9
to_list, get_cls_kwargs, deprecated,\
11
from sqlalchemy.orm import (
12
EXT_CONTINUE, MapperExtension, class_mapper, object_session
7
from sqlalchemy import exc as sa_exc
8
from sqlalchemy.util import ScopedRegistry, ThreadLocalRegistry, warn
9
from sqlalchemy.orm import class_mapper
14
10
from sqlalchemy.orm import exc as orm_exc
15
11
from sqlalchemy.orm.session import Session
21
17
class ScopedSession(object):
22
18
"""Provides thread-local management of Sessions.
20
Typical invocation is via the :func:`.scoped_session`
26
23
Session = scoped_session(sessionmaker())
28
... use Session normally.
30
The internal registry is accessible as well,
25
The internal registry is accessible,
31
26
and by default is an instance of :class:`.ThreadLocalRegistry`.
28
See also: :ref:`unitofwork_contextual`.
64
59
self.registry().close()
65
60
self.registry.clear()
67
@deprecated("0.5", ":meth:`.ScopedSession.mapper` is deprecated. "
68
"Please see http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SessionAwareMapper "
69
"for information on how to replicate its behavior.")
70
def mapper(self, *args, **kwargs):
71
"""return a :func:`.mapper` function which associates this ScopedSession with the Mapper.
75
from sqlalchemy.orm import mapper
77
extension_args = dict((arg, kwargs.pop(arg))
78
for arg in get_cls_kwargs(_ScopedExt)
81
kwargs['extension'] = extension = to_list(kwargs.get('extension', []))
83
extension.append(self.extension.configure(**extension_args))
85
extension.append(self.extension)
86
return mapper(*args, **kwargs)
88
62
def configure(self, **kwargs):
89
63
"""reconfigure the sessionmaker used by this ScopedSession."""
157
131
for prop in ('close_all', 'object_session', 'identity_key'):
158
132
setattr(ScopedSession, prop, clslevel(prop))
160
class _ScopedExt(MapperExtension):
161
def __init__(self, context, validate=False, save_on_init=True):
162
self.context = context
163
self.validate = validate
164
self.save_on_init = save_on_init
165
self.set_kwargs_on_init = True
167
def validating(self):
168
return _ScopedExt(self.context, validate=True)
170
def configure(self, **kwargs):
171
return _ScopedExt(self.context, **kwargs)
173
def instrument_class(self, mapper, class_):
175
def __getattr__(s, key):
176
return getattr(self.context.registry().query(class_), key)
178
return self.context.registry().query(class_)
179
def __get__(self, instance, cls):
182
if not 'query' in class_.__dict__:
183
class_.query = query()
185
if self.set_kwargs_on_init and class_.__init__ is object.__init__:
186
class_.__init__ = self._default__init__(mapper)
188
def _default__init__(ext, mapper):
189
def __init__(self, **kwargs):
190
for key, value in kwargs.iteritems():
192
if not mapper.get_property(key, resolve_synonyms=False,
194
raise sa_exc.ArgumentError(
195
"Invalid __init__ argument: '%s'" % key)
196
setattr(self, key, value)
199
def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
200
if self.save_on_init:
201
session = kwargs.pop('_sa_session', None)
203
session = self.context.registry()
204
session._save_without_cascade(instance)
207
def init_failed(self, mapper, class_, oldinit, instance, args, kwargs):
208
sess = object_session(instance)
210
sess.expunge(instance)
213
def dispose_class(self, mapper, class_):
214
if hasattr(class_, 'query'):
215
delattr(class_, 'query')