]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Added a new attribute :attr:`.Session.info` to :class:`.Session`;
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Aug 2013 16:39:29 +0000 (12:39 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Aug 2013 16:39:29 +0000 (12:39 -0400)
this is a dictionary where applications can store arbitrary
data local to a :class:`.Session`.
The contents of :attr:`.Session.info` can be also be initialized
using the ``info`` argument of :class:`.Session` or
:class:`.sessionmaker`.

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/orm/session.py
test/orm/test_session.py

index 666729e8d44753c27a684eca2d77cbcea07693ce..03e2ba51563a508a52692f2546cca23de2284236 100644 (file)
@@ -6,6 +6,16 @@
 .. changelog::
     :version: 0.9.0
 
+    .. change::
+        :tags: orm, feature, orm
+
+        Added a new attribute :attr:`.Session.info` to :class:`.Session`;
+        this is a dictionary where applications can store arbitrary
+        data local to a :class:`.Session`.
+        The contents of :attr:`.Session.info` can be also be initialized
+        using the ``info`` argument of :class:`.Session` or
+        :class:`.sessionmaker`.
+
     .. change::
         :tags: mysql, bug
         :tickets: 2791
index 5a4486eef5bc71b2de966e8f1b9440d68fc0f78b..e5742f018c50a0ca509d8738b709d6566b376718 100644 (file)
@@ -469,6 +469,7 @@ class Session(_SessionClassMethods):
                 _enable_transaction_accounting=True,
                  autocommit=False, twophase=False,
                  weak_identity_map=True, binds=None, extension=None,
+                 info=None,
                  query_cls=query.Query):
         """Construct a new Session.
 
@@ -557,6 +558,14 @@ class Session(_SessionClassMethods):
            flush events, as well as a post-rollback event. **Deprecated.**
            Please see :class:`.SessionEvents`.
 
+        :param info: optional dictionary of arbitrary data to be associated
+           with this :class:`.Session`.  Is available via the :attr:`.Session.info`
+           attribute.  Note the dictionary is copied at construction time so
+           that modifications to the per-:class:`.Session` dictionary will be local
+           to that :class:`.Session`.
+
+           .. versionadded:: 0.9.0
+
         :param query_cls:  Class which should be used to create new Query
            objects, as returned by the ``query()`` method. Defaults to
            :class:`~sqlalchemy.orm.query.Query`.
@@ -599,6 +608,8 @@ class Session(_SessionClassMethods):
         self._enable_transaction_accounting = _enable_transaction_accounting
         self.twophase = twophase
         self._query_cls = query_cls
+        if info:
+            self.info.update(info)
 
         if extension:
             for ext in util.to_list(extension):
@@ -622,6 +633,21 @@ class Session(_SessionClassMethods):
     transaction = None
     """The current active or inactive :class:`.SessionTransaction`."""
 
+    @util.memoized_property
+    def info(self):
+        """A user-modifiable dictionary.
+
+        The initial value of this dictioanry can be populated using the
+        ``info`` argument to the :class:`.Session` constructor or
+        :class:`.sessionmaker` constructor or factory methods.  The dictionary
+        here is always local to this :class:`.Session` and can be modified
+        independently of all other :class:`.Session` objects.
+
+        .. versionadded:: 0.9.0
+
+        """
+        return {}
+
     def begin(self, subtransactions=False, nested=False):
         """Begin a transaction on this Session.
 
@@ -2196,7 +2222,8 @@ class sessionmaker(_SessionClassMethods):
 
     def __init__(self, bind=None, class_=Session, autoflush=True,
                         autocommit=False,
-                        expire_on_commit=True, **kw):
+                        expire_on_commit=True,
+                        info=None, **kw):
         """Construct a new :class:`.sessionmaker`.
 
         All arguments here except for ``class_`` correspond to arguments
@@ -2213,6 +2240,13 @@ class sessionmaker(_SessionClassMethods):
          :class:`.Session` objects.
         :param expire_on_commit=True: the expire_on_commit setting to use
          with newly created :class:`.Session` objects.
+        :param info: optional dictionary of information that will be available
+         via :attr:`.Session.info`.  Note this dictionary is *updated*, not
+         replaced, when the ``info`` parameter is specified to the specific
+         :class:`.Session` construction operation.
+
+         .. versionadded:: 0.9.0
+
         :param \**kw: all other keyword arguments are passed to the constructor
          of newly created :class:`.Session` objects.
 
@@ -2221,6 +2255,7 @@ class sessionmaker(_SessionClassMethods):
         kw['autoflush'] = autoflush
         kw['autocommit'] = autocommit
         kw['expire_on_commit'] = expire_on_commit
+        kw['info'] = info
         self.kw = kw
         # make our own subclass of the given class, so that
         # events can be associated with it specifically.
@@ -2238,7 +2273,12 @@ class sessionmaker(_SessionClassMethods):
 
         """
         for k, v in self.kw.items():
-            local_kw.setdefault(k, v)
+            if k == 'info' and 'info' in local_kw:
+                d = v.copy()
+                d.update(local_kw['info'])
+                local_kw['info'] = d
+            else:
+                local_kw.setdefault(k, v)
         return self.class_(**local_kw)
 
     def configure(self, **new_kw):
index 45164483b62f3892cb89f7b14c9a801a47a52f7e..a4d5b6ce62ece8406cb99c8518cb31009c6b2c9b 100644 (file)
@@ -395,6 +395,23 @@ class SessionStateTest(_fixtures.FixtureTest):
     run_inserts = None
 
 
+    def test_info(self):
+        s = Session()
+        eq_(s.info, {})
+
+        maker = sessionmaker(info={"global": True, "s1": 5})
+
+        s1 = maker()
+        s2 = maker(info={"s1": 6, "s2": True})
+
+        eq_(s1.info, {"global": True, "s1": 5})
+        eq_(s2.info, {"global": True, "s1": 6, "s2": True})
+        s2.info["global"] = False
+        s2.info["s1"] = 7
+
+        s3 = maker()
+        eq_(s3.info, {"global": True, "s1": 5})
+
     @testing.requires.independent_connections
     @engines.close_open_connections
     def test_autoflush(self):