summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-08-02 05:42:49 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-08-02 05:42:49 +0000
commitb8b51fe4379936fe142c875ea0f17da14a12c27d (patch)
tree987fc4033cad747f0decfa80e38708a13d812d4c /lib/sqlalchemy/orm
parent9f23ec7423e98305f43a0b7a7ef894da74325329 (diff)
downloadsqlalchemy-b8b51fe4379936fe142c875ea0f17da14a12c27d.tar.gz
- sessionmaker module is out, replaced with simple function in session.py
- scoping/class instrumenting behavior of sessionmaker moved into new scoping module which implements scoped_session() (subject to potential name change) - SessionContext / assignmapper are deprecated, replaced with scoped_session()
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/__init__.py10
-rw-r--r--lib/sqlalchemy/orm/scoping.py111
-rw-r--r--lib/sqlalchemy/orm/session.py92
-rw-r--r--lib/sqlalchemy/orm/sessionmaker.py105
4 files changed, 131 insertions, 187 deletions
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 26b583bb1..646135e8c 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -21,25 +21,25 @@ from sqlalchemy.orm.query import Query
from sqlalchemy.orm.util import polymorphic_union
from sqlalchemy.orm.session import Session as _Session
from sqlalchemy.orm.session import object_session, attribute_manager, sessionmaker
-from sqlalchemy.orm.sessionmaker import sessionmaker
+from sqlalchemy.orm.scoping import ScopedSession as scoped_session
__all__ = [ 'relation', 'column_property', 'composite', 'backref', 'eagerload',
'eagerload_all', 'lazyload', 'noload', 'deferred', 'defer',
'undefer', 'undefer_group', 'extension', 'mapper', 'clear_mappers',
'compile_mappers', 'class_mapper', 'object_mapper', 'sessionmaker',
- 'dynamic_loader', 'MapperExtension', 'Query', 'polymorphic_union',
+ 'scoped_session', 'dynamic_loader', 'MapperExtension', 'Query', 'polymorphic_union',
'create_session', 'synonym', 'contains_alias',
'contains_eager', 'EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS',
'object_session', 'PropComparator' ]
-
def create_session(bind=None, **kwargs):
- """create a new version 0.3-style [sqlalchemy.orm.session#Session].
+ """create a new [sqlalchemy.orm.session#Session].
The session by default does not begin a transaction, and requires that
flush() be called explicitly in order to persist results to the database.
+
+ It is recommended to use the sessionmaker() function instead of create_session().
"""
- sautil.warn_deprecated("create_session() is deprecated. Use Session=sessionmaker() instead.")
kwargs.setdefault('autoflush', False)
kwargs.setdefault('transactional', False)
return _Session(bind=bind, **kwargs)
diff --git a/lib/sqlalchemy/orm/scoping.py b/lib/sqlalchemy/orm/scoping.py
new file mode 100644
index 000000000..3ae63b49a
--- /dev/null
+++ b/lib/sqlalchemy/orm/scoping.py
@@ -0,0 +1,111 @@
+from sqlalchemy.util import ScopedRegistry, warn_deprecated
+from sqlalchemy.orm import MapperExtension, EXT_CONTINUE
+from sqlalchemy.orm.session import Session
+from sqlalchemy.orm.mapper import global_extensions
+from sqlalchemy import exceptions
+import types
+
+__all__ = ['ScopedSession']
+
+
+class ScopedSession(object):
+ """Provides thread-local management of Sessions.
+
+ Usage::
+
+ Session = scoped_session(sessionmaker(autoflush=True), enhance_classes=True)
+
+ """
+
+ def __init__(self, session_factory, scopefunc=None, enhance_classes=False):
+ self.session_factory = session_factory
+ self.enhance_classes = enhance_classes
+ self.registry = ScopedRegistry(session_factory, scopefunc)
+ if self.enhance_classes:
+ global_extensions.append(_ScopedExt(self))
+
+ def __call__(self, **kwargs):
+ if len(kwargs):
+ scope = kwargs.pop('scope', False)
+ if scope is not None:
+ if self.registry.has():
+ raise exceptions.InvalidRequestError("Scoped session is already present; no new arguments may be specified.")
+ else:
+ sess = self.session_factory(**kwargs)
+ self.registry.set(sess)
+ return sess
+ else:
+ return self.session_factory(**kwargs)
+ else:
+ return self.registry()
+
+ def configure(self, **kwargs):
+ """reconfigure the sessionmaker used by this SessionContext"""
+ self.session_factory.configure(**kwargs)
+
+def instrument(name):
+ def do(self, *args, **kwargs):
+ return getattr(self.registry(), name)(*args, **kwargs)
+ return do
+for meth in ('get', 'close', 'save', 'commit', 'update', 'flush', 'query', 'delete'):
+ setattr(ScopedSession, meth, instrument(meth))
+
+def makeprop(name):
+ def set(self, attr):
+ setattr(self.registry(), name, attr)
+ def get(self):
+ return getattr(self.registry(), name)
+ return property(get, set)
+for prop in ('bind', 'dirty', 'identity_map'):
+ setattr(ScopedSession, prop, makeprop(prop))
+
+def clslevel(name):
+ def do(cls, *args,**kwargs):
+ return getattr(Session, name)(*args, **kwargs)
+ return classmethod(do)
+for prop in ('close_all',):
+ setattr(ScopedSession, prop, clslevel(prop))
+
+class _ScopedExt(MapperExtension):
+ def __init__(self, context):
+ self.context = context
+
+ def get_session(self):
+ return self.context.registry()
+
+ def instrument_class(self, mapper, class_):
+ class query(object):
+ def __getattr__(self, key):
+ return getattr(registry().query(class_), key)
+ def __call__(self):
+ return registry().query(class_)
+
+ if not hasattr(class_, 'query'):
+ class_.query = query()
+
+ def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
+ session = kwargs.pop('_sa_session', self.context.registry())
+ if not isinstance(oldinit, types.MethodType):
+ for key, value in kwargs.items():
+ #if validate:
+ # if not self.mapper.get_property(key, resolve_synonyms=False, raiseerr=False):
+ # raise exceptions.ArgumentError("Invalid __init__ argument: '%s'" % key)
+ setattr(instance, key, value)
+ session._save_impl(instance, entity_name=kwargs.pop('_sa_entity_name', None))
+ return EXT_CONTINUE
+
+ def init_failed(self, mapper, class_, oldinit, instance, args, kwargs):
+ object_session(instance).expunge(instance)
+ return EXT_CONTINUE
+
+ def dispose_class(self, mapper, class_):
+ if hasattr(class_, '__init__') and hasattr(class_.__init__, '_oldinit'):
+ if class_.__init__._oldinit is not None:
+ class_.__init__ = class_.__init__._oldinit
+ else:
+ delattr(class_, '__init__')
+ if hasattr(class_, 'query'):
+ delattr(class_, 'query')
+
+
+
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 996c7d8a0..f982da536 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -14,93 +14,31 @@ from sqlalchemy.orm.mapper import global_extensions
__all__ = ['Session', 'SessionTransaction']
-def sessionmaker(autoflush, transactional, bind=None, scope=None, enhance_classes=False, **kwargs):
+def sessionmaker(autoflush=True, transactional=True, bind=None, **kwargs):
"""Generate a Session configuration."""
+
+ kwargs['bind'] = bind
+ kwargs['autoflush'] = autoflush
+ kwargs['transactional'] = transactional
- if enhance_classes and scope is None:
- raise exceptions.InvalidRequestError("enhance_classes requires a non-None 'scope' argument, so that mappers can automatically locate a Session already in progress.")
-
class Sess(Session):
def __init__(self, **local_kwargs):
- local_kwargs.setdefault('bind', bind)
- local_kwargs.setdefault('autoflush', autoflush)
- local_kwargs.setdefault('transactional', transactional)
for k in kwargs:
local_kwargs.setdefault(k, kwargs[k])
super(Sess, self).__init__(**local_kwargs)
- if scope=="thread":
- registry = util.ScopedRegistry(Sess, scopefunc=None)
-
- if enhance_classes:
- class SessionContextExt(MapperExtension):
- def get_session(self):
- return registry()
-
- def instrument_class(self, mapper, class_):
- class query(object):
- def __getattr__(self, key):
- return getattr(registry().query(class_), key)
- def __call__(self):
- return registry().query(class_)
-
- if not hasattr(class_, 'query'):
- class_.query = query()
-
- def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
- session = kwargs.pop('_sa_session', registry())
- if not isinstance(oldinit, types.MethodType):
- for key, value in kwargs.items():
- #if validate:
- # if not self.mapper.get_property(key, resolve_synonyms=False, raiseerr=False):
- # raise exceptions.ArgumentError("Invalid __init__ argument: '%s'" % key)
- setattr(instance, key, value)
- session._save_impl(instance, entity_name=kwargs.pop('_sa_entity_name', None))
- return EXT_CONTINUE
-
- def init_failed(self, mapper, class_, oldinit, instance, args, kwargs):
- object_session(instance).expunge(instance)
- return EXT_CONTINUE
-
- def dispose_class(self, mapper, class_):
- if hasattr(class_, '__init__') and hasattr(class_.__init__, '_oldinit'):
- if class_.__init__._oldinit is not None:
- class_.__init__ = class_.__init__._oldinit
- else:
- delattr(class_, '__init__')
- if hasattr(class_, 'query'):
- delattr(class_, 'query')
-
- global_extensions.append(SessionContextExt())
+ def configure(self, **new_kwargs):
+ """(re)configure the arguments for this sessionmaker.
- default_scope=scope
- class ScopedSess(Sess):
- def __new__(cls, **kwargs):
- if len(kwargs):
- scope = kwargs.pop('scope', default_scope)
- if scope is not None:
- if registry.has():
- raise exceptions.InvalidRequestError("Scoped session is already present; no new arguments may be specified.")
- else:
- sess = Sess(**kwargs)
- registry.set(sess)
- return sess
- else:
- return Sess(**kwargs)
- else:
- return registry()
- def instrument(name):
- def do(cls, *args, **kwargs):
- return getattr(registry(), name)(*args, **kwargs)
- return classmethod(do)
- for meth in ('get', 'close', 'save', 'commit', 'update', 'flush', 'query', 'delete'):
- setattr(ScopedSess, meth, instrument(meth))
+ e.g.
+ Session = sessionmaker()
+ Session.configure(bind=create_engine('sqlite://'))
+ """
- return ScopedSess
- elif scope is not None:
- raise exceptions.ArgumentError("Unknown scope '%s'" % scope)
- else:
- return session
+ kwargs.update(new_kwargs)
+ configure = classmethod(configure)
+
+ return Sess
class SessionTransaction(object):
"""Represents a Session-level Transaction.
diff --git a/lib/sqlalchemy/orm/sessionmaker.py b/lib/sqlalchemy/orm/sessionmaker.py
deleted file mode 100644
index 13e28fd1a..000000000
--- a/lib/sqlalchemy/orm/sessionmaker.py
+++ /dev/null
@@ -1,105 +0,0 @@
-import types
-
-from sqlalchemy import util, exceptions
-from sqlalchemy.orm.session import Session
-from sqlalchemy.orm import query, util as mapperutil, MapperExtension, EXT_CONTINUE
-from sqlalchemy.orm.mapper import global_extensions
-
-def sessionmaker(autoflush, transactional, bind=None, scope=None, enhance_classes=False, **kwargs):
- """Generate a Session configuration."""
-
- if enhance_classes and scope is None:
- raise exceptions.InvalidRequestError("enhance_classes requires a non-None 'scope' argument, so that mappers can automatically locate a Session already in progress.")
-
- class Sess(Session):
- def __init__(self, **local_kwargs):
- local_kwargs.setdefault('bind', bind)
- local_kwargs.setdefault('autoflush', autoflush)
- local_kwargs.setdefault('transactional', transactional)
- for k in kwargs:
- local_kwargs.setdefault(k, kwargs[k])
- super(Sess, self).__init__(**local_kwargs)
-
- if scope=="thread":
- registry = util.ScopedRegistry(Sess, scopefunc=None)
-
- if enhance_classes:
- class SessionContextExt(MapperExtension):
- def get_session(self):
- return registry()
-
- def instrument_class(self, mapper, class_):
- class query(object):
- def __getattr__(self, key):
- return getattr(registry().query(class_), key)
- def __call__(self):
- return registry().query(class_)
-
- if not hasattr(class_, 'query'):
- class_.query = query()
-
- def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
- session = kwargs.pop('_sa_session', registry())
- if not isinstance(oldinit, types.MethodType):
- for key, value in kwargs.items():
- #if validate:
- # if not self.mapper.get_property(key, resolve_synonyms=False, raiseerr=False):
- # raise exceptions.ArgumentError("Invalid __init__ argument: '%s'" % key)
- setattr(instance, key, value)
- session._save_impl(instance, entity_name=kwargs.pop('_sa_entity_name', None))
- return EXT_CONTINUE
-
- def init_failed(self, mapper, class_, oldinit, instance, args, kwargs):
- object_session(instance).expunge(instance)
- return EXT_CONTINUE
-
- def dispose_class(self, mapper, class_):
- if hasattr(class_, '__init__') and hasattr(class_.__init__, '_oldinit'):
- if class_.__init__._oldinit is not None:
- class_.__init__ = class_.__init__._oldinit
- else:
- delattr(class_, '__init__')
- if hasattr(class_, 'query'):
- delattr(class_, 'query')
-
- global_extensions.append(SessionContextExt())
-
- default_scope=scope
-
- class ScopedSess(Sess):
- def __call__(self, **kwargs):
- if len(kwargs):
- scope = kwargs.pop('scope', default_scope)
- if scope is not None:
- if registry.has():
- raise exceptions.InvalidRequestError("Scoped session is already present; no new arguments may be specified.")
- else:
- sess = Sess(**kwargs)
- registry.set(sess)
- return sess
- else:
- return Sess(**kwargs)
- else:
- return registry()
-
- def instrument(name):
- def do(cls, *args, **kwargs):
- return getattr(registry(), name)(*args, **kwargs)
- return do
- for meth in ('get', 'close', 'save', 'commit', 'update', 'flush', 'query', 'delete'):
- setattr(ScopedSess, meth, instrument(meth))
-
- def makeprop(name):
- def set(self, attr):
- setattr(registry(), name, attr)
- def get(self):
- return getattr(registry(), name)
- return property(get, set)
- for prop in ('bind', 'dirty', 'identity_map'):
- setattr(ScopedSess, prop, makeprop(prop))
-
- return ScopedSess()
- elif scope is not None:
- raise exceptions.ArgumentError("Unknown scope '%s'" % scope)
- else:
- return Sess