diff options
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 19 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/state.py | 29 |
2 files changed, 39 insertions, 9 deletions
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index d5f418b1c..a3ec360d0 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -54,17 +54,14 @@ _sessions = weakref.WeakValueDictionary() """Weak-referencing dictionary of :class:`.Session` objects. """ +statelib._sessions = _sessions + def _state_session(state): """Given an :class:`.InstanceState`, return the :class:`.Session` associated, if any. """ - if state.session_id: - try: - return _sessions[state.session_id] - except KeyError: - pass - return None + return state.session class _SessionClassMethods(object): @@ -1273,7 +1270,13 @@ class Session(_SessionClassMethods): ) def begin(self, subtransactions=False, nested=False, _subtrans=False): """Begin a transaction, or nested transaction, - on this :class:`.Session`. + on this :class:`.Session`, if one is not already begun. + + The :class:`_orm.Session` object features **autobegin** behavior, + so that normally it is not necessary to call the + :meth:`_orm.Session.begin` + method explicitly. However, it may be used in order to control + the scope of when the transactional state is begun. When used to begin the outermost transaction, an error is raised if this :class:`.Session` is already inside of a transaction. @@ -1294,6 +1297,8 @@ class Session(_SessionClassMethods): .. seealso:: + :ref:`session_autobegin` + :ref:`unitofwork_transaction` :meth:`.Session.begin_nested` diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index cda98b890..08390328e 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -31,6 +31,10 @@ from .. import inspection from .. import util +# late-populated by session.py +_sessions = None + + @inspection._self_inspects class InstanceState(interfaces.InspectionAttrInfo): """tracks state information at the instance level. @@ -247,7 +251,6 @@ class InstanceState(interfaces.InspectionAttrInfo): self._last_known_values[key] = NO_VALUE @property - @util.preload_module("sqlalchemy.orm.session") def session(self): """Return the owning :class:`.Session` for this instance, or ``None`` if none available. @@ -260,7 +263,12 @@ class InstanceState(interfaces.InspectionAttrInfo): fully detached under normal circumstances. """ - return util.preloaded.orm_session._state_session(self) + if self.session_id: + try: + return _sessions[self.session_id] + except KeyError: + pass + return None @property def object(self): @@ -754,7 +762,10 @@ class InstanceState(interfaces.InspectionAttrInfo): self.modified = True instance_dict = self._instance_dict() if instance_dict: + has_modified = bool(instance_dict._modified) instance_dict._modified.add(self) + else: + has_modified = False # only create _strong_obj link if attached # to a session @@ -763,6 +774,20 @@ class InstanceState(interfaces.InspectionAttrInfo): if self.session_id: self._strong_obj = inst + # if identity map already had modified objects, + # assume autobegin already occurred, else check + # for autobegin + if not has_modified: + # inline of autobegin, to ensure session transaction + # snapshot is established + try: + session = _sessions[self.session_id] + except KeyError: + pass + else: + if session._transaction is None: + session._autobegin() + if inst is None and attr: raise orm_exc.ObjectDereferencedError( "Can't emit change event for attribute '%s' - " |
