diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-08-01 20:52:26 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-08-01 20:52:26 +0000 |
commit | f75faa7cb489a343a2f26afd32c42a378591d6ad (patch) | |
tree | 231d0fa98f7aea1ac7d80c87e674ecb896fe79aa /lib/sqlalchemy | |
parent | 8a5d576872e7e16a419b08770a6000a6a8001ef7 (diff) | |
download | sqlalchemy-f75faa7cb489a343a2f26afd32c42a378591d6ad.tar.gz |
- SessionContext and assignmapper are deprecated
- Session function is removed
- all replaced with new sessionmaker() function. description at:
http://www.sqlalchemy.org/trac/wiki/WhatsNewIn04#create_sessionSessionContextassignmapperDeprecated
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r-- | lib/sqlalchemy/ext/sessioncontext.py | 5 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/__init__.py | 26 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/session.py | 95 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/sessionmaker.py | 94 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/util.py | 1 | ||||
-rw-r--r-- | lib/sqlalchemy/util.py | 5 |
8 files changed, 210 insertions, 31 deletions
diff --git a/lib/sqlalchemy/ext/sessioncontext.py b/lib/sqlalchemy/ext/sessioncontext.py index 91c03d3c3..8221bc495 100644 --- a/lib/sqlalchemy/ext/sessioncontext.py +++ b/lib/sqlalchemy/ext/sessioncontext.py @@ -1,4 +1,4 @@ -from sqlalchemy.util import ScopedRegistry +from sqlalchemy.util import ScopedRegistry, warn_deprecated from sqlalchemy.orm import create_session, object_session, MapperExtension, EXT_CONTINUE __all__ = ['SessionContext', 'SessionContextExt'] @@ -25,6 +25,7 @@ class SessionContext(object): """ def __init__(self, session_factory=None, scopefunc=None): + warn_deprecated("SessionContext is deprecated. Use Session=sessionmaker(scope='thread').") if session_factory is None: session_factory = create_session self.registry = ScopedRegistry(session_factory, scopefunc) @@ -63,7 +64,7 @@ class SessionContextExt(MapperExtension): def get_session(self): return self.context.current - def init_instance(self, mapper, class_, instance, args, kwargs): + def init_instance(self, mapper, class_, oldinit, instance, args, kwargs): session = kwargs.pop('_sa_session', self.context.current) session._save_impl(instance, entity_name=kwargs.pop('_sa_entity_name', None)) return EXT_CONTINUE diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index 3c221bb66..26b583bb1 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -20,14 +20,15 @@ from sqlalchemy.orm import collections, strategies 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 +from sqlalchemy.orm.session import object_session, attribute_manager, sessionmaker +from sqlalchemy.orm.sessionmaker import sessionmaker __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', + 'compile_mappers', 'class_mapper', 'object_mapper', 'sessionmaker', 'dynamic_loader', 'MapperExtension', 'Query', 'polymorphic_union', - 'create_session', 'Session', 'synonym', 'contains_alias', + 'create_session', 'synonym', 'contains_alias', 'contains_eager', 'EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS', 'object_session', 'PropComparator' ] @@ -38,28 +39,11 @@ def create_session(bind=None, **kwargs): The session by default does not begin a transaction, and requires that flush() be called explicitly in order to persist results to the database. """ - + sautil.warn_deprecated("create_session() is deprecated. Use Session=sessionmaker() instead.") kwargs.setdefault('autoflush', False) kwargs.setdefault('transactional', False) return _Session(bind=bind, **kwargs) -class Session(_Session): - """front-end for a [sqlalchemy.orm.session#Session]. By default, - produces an autoflushing, transactional session.""" - - def __init__(self, bind=None, **kwargs): - """create a new transactional [sqlalchemy.orm.session#Session]. - - The session starts a new transaction for each database accessed. To - commit the transaction, use the commit() method. SQL is issued for - write operations (i.e. flushes) automatically in most cases, before each query - and during commit. - """ - - kwargs.setdefault('autoflush', True) - kwargs.setdefault('transactional', True) - super(Session, self).__init__(bind=bind, **kwargs) - def relation(argument, secondary=None, **kwargs): """Provide a relationship of a primary Mapper to a secondary Mapper. diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 271846ca8..abaeff49c 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -34,11 +34,14 @@ class MapperExtension(object): EXT_PASS is a synonym for EXT_CONTINUE and is provided for backward compatibility. """ - - def init_instance(self, mapper, class_, instance, args, kwargs): + + def instrument_class(self, mapper, class_): + return EXT_CONTINUE + + def init_instance(self, mapper, class_, oldinit, instance, args, kwargs): return EXT_CONTINUE - def init_failed(self, mapper, class_, instance, args, kwargs): + def init_failed(self, mapper, class_, oldinit, instance, args, kwargs): return EXT_CONTINUE def get_session(self): diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index debce60f2..af7c9d4cf 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -304,6 +304,8 @@ class Mapper(object): for ext in extlist: self.extension.append(ext) + self.extension.instrument_class(self, self.class_) + def _compile_inheritance(self): """Determine if this Mapper inherits from another mapper, and if so calculates the mapped_table for this Mapper taking the @@ -679,7 +681,7 @@ class Mapper(object): oldinit = self.class_.__init__ def init(instance, *args, **kwargs): self.compile() - self.extension.init_instance(self, self.class_, instance, args, kwargs) + self.extension.init_instance(self, self.class_, oldinit, instance, args, kwargs) if oldinit is not None: try: @@ -687,7 +689,7 @@ class Mapper(object): except: # call init_failed but suppress exceptions into warnings so that original __init__ # exception is raised - util.warn_exception(self.extension.init_failed, self, self.class_, instance, args, kwargs) + util.warn_exception(self.extension.init_failed, self, self.class_, oldinit, instance, args, kwargs) raise # override oldinit, ensuring that its not already a Mapper-decorated init method diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index b957f822f..996c7d8a0 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -4,13 +4,104 @@ # This module is part of SQLAlchemy and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -import weakref +import weakref, types from sqlalchemy import util, exceptions, sql, engine -from sqlalchemy.orm import unitofwork, query, util as mapperutil +from sqlalchemy.orm import unitofwork, query, util as mapperutil, MapperExtension, EXT_CONTINUE from sqlalchemy.orm.mapper import object_mapper as _object_mapper from sqlalchemy.orm.mapper import class_mapper as _class_mapper +from sqlalchemy.orm.mapper import global_extensions +__all__ = ['Session', 'SessionTransaction'] + +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 __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)) + + return ScopedSess + elif scope is not None: + raise exceptions.ArgumentError("Unknown scope '%s'" % scope) + else: + return session + class SessionTransaction(object): """Represents a Session-level Transaction. diff --git a/lib/sqlalchemy/orm/sessionmaker.py b/lib/sqlalchemy/orm/sessionmaker.py new file mode 100644 index 000000000..42064c5b8 --- /dev/null +++ b/lib/sqlalchemy/orm/sessionmaker.py @@ -0,0 +1,94 @@ +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 __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)) + + return ScopedSess + elif scope is not None: + raise exceptions.ArgumentError("Unknown scope '%s'" % scope) + else: + return Sess diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index 6a9c4164f..727be50c6 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -140,6 +140,7 @@ class ExtensionCarrier(MapperExtension): return EXT_CONTINUE return _do + instrument_class = _create_do('instrument_class') init_instance = _create_do('init_instance') init_failed = _create_do('init_failed') dispose_class = _create_do('dispose_class') diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py index 7391d86fd..ea1c8286a 100644 --- a/lib/sqlalchemy/util.py +++ b/lib/sqlalchemy/util.py @@ -543,7 +543,10 @@ class ScopedRegistry(object): return self.registry[key] except KeyError: return self.registry.setdefault(key, self.createfunc()) - + + def has(self): + return self._get_key() in self.registry + def set(self, obj): self.registry[self._get_key()] = obj |