)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7249,"name":"Ann Taraday","email":"akamyshnikova@mirantis.com","username":"AKamyshnikova"},"change_message_id":"45cc9e8393ba2aa5a159038ced6231eafb3b0d29","unresolved":false,"context_lines":[{"line_number":24,"context_line":"some very old documentation in session.py.  The enginefacade"},{"line_number":25,"context_line":"system should be preferred moving forward."},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"bp/make-enginefacade-a-facade"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"Change-Id: I9a3d0c26bb727eb2c0bd823b9a12fde57cc7c9c3"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"5a890539_2264b8e3","line":27,"updated":"2014-12-04 11:24:24.000000000","message":"Should be Implements: blueprint make-enginefacade-a-facade to provide a link for it.","commit_id":"30415656f863984bf1ac68ebd67c3816f04fd07f"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"456b2e43d6727d2fc89360ead17ab4657d4a4818","unresolved":false,"context_lines":[{"line_number":24,"context_line":"some very old documentation in session.py.  The enginefacade"},{"line_number":25,"context_line":"system should be preferred moving forward."},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"bp/make-enginefacade-a-facade"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"Change-Id: I9a3d0c26bb727eb2c0bd823b9a12fde57cc7c9c3"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"5a890539_c75859fb","line":27,"in_reply_to":"5a890539_2264b8e3","updated":"2014-12-04 17:06:32.000000000","message":"yeah i was trying to find an example to remind me of what it looked like, but could only find a DHellman example where he was doing it that way (I knew it was incorrect) :)","commit_id":"30415656f863984bf1ac68ebd67c3816f04fd07f"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"0115b9d99b18a3c388789a7786c4e49d818ac70c","unresolved":false,"context_lines":[{"line_number":24,"context_line":"some very old documentation in session.py.  The enginefacade"},{"line_number":25,"context_line":"system should be preferred moving forward."},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"bp/make-enginefacade-a-facade"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"Change-Id: I9a3d0c26bb727eb2c0bd823b9a12fde57cc7c9c3"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"5a890539_c7269966","line":27,"in_reply_to":"5a890539_c75859fb","updated":"2014-12-04 17:09:31.000000000","message":"See https://wiki.openstack.org/wiki/GitCommitMessages#Including_external_references","commit_id":"30415656f863984bf1ac68ebd67c3816f04fd07f"}],"doc/source/usage.rst":[{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"232aefb2e5b3903ff8d0d296ba25143b41f05275","unresolved":false,"context_lines":[{"line_number":87,"context_line":""},{"line_number":88,"context_line":"    from oslo_db.sqlalchemy import enginefacade"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    enginefacade.configure("},{"line_number":91,"context_line":"        sqlite_fk\u003dTrue,"},{"line_number":92,"context_line":"        max_retries\u003d5,"},{"line_number":93,"context_line":"        mysql_sql_mode\u003d\u0027ANSI\u0027"}],"source_content_type":"text/x-rst","patch_set":44,"id":"3afb71cf_ea07467f","line":90,"updated":"2015-06-08 16:02:48.000000000","message":"+1 for keeping APIs consistent with SQLAlchemy/alembic","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"}],"oslo/db/sqlalchemy/enginefacade.py":[{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":292,"context_line":"    def _start(self, conf\u003d_NOTSET, connection\u003dNone, slave_connection\u003dNone):"},{"line_number":293,"context_line":"        with self._start_lock:"},{"line_number":294,"context_line":"            # cancel other threads from entering"},{"line_number":295,"context_line":"            # after started has already proceeded"},{"line_number":296,"context_line":"            if self._started:"},{"line_number":297,"context_line":"                return"},{"line_number":298,"context_line":"            self._started \u003d True"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_6d1da373","line":295,"updated":"2014-12-08 12:00:04.000000000","message":"Nit: This reads like it was edited and not re-proofed :) I\u0027m not sure what this comment means. Are you commenting on the guard around the check self._started? Is that s/cancel/prevent/, and you\u0027re pointing out that this is a synchronized section?\n\nIncidentally, in other languages it\u0027s a fairly common pattern to do:\n\nif _started { return }\nlock()\nif _started { return }\n_started \u003d True\n...\n\nThis is a good pattern if:\n\n* _started can read and set atomically\n* lock() is somewhat expensive\n* We expect _started to be normally true\n\nI\u0027m confident that _started is read and set atomically in this context. However, I\u0027m not sure how expensive locking is, and I\u0027m still reading so don\u0027t know yet what our expectations are wrt _started\u0027s usual value.\n\nActually meh, this is Python: why I am even considering performance? As long as it\u0027s safe, it\u0027s fine.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":292,"context_line":"    def _start(self, conf\u003d_NOTSET, connection\u003dNone, slave_connection\u003dNone):"},{"line_number":293,"context_line":"        with self._start_lock:"},{"line_number":294,"context_line":"            # cancel other threads from entering"},{"line_number":295,"context_line":"            # after started has already proceeded"},{"line_number":296,"context_line":"            if self._started:"},{"line_number":297,"context_line":"                return"},{"line_number":298,"context_line":"            self._started \u003d True"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_02d13057","line":295,"in_reply_to":"3a961159_6d1da373","updated":"2014-12-08 23:11:12.000000000","message":"i can edit the comment.  As far as the _started check on top, normally I would do that, however we are doing that check on the outside, as you can see in def _create_connection() and def _create_session(), before we call self._started().  The method here won\u0027t be called after the first 500 milliseconds that the app has been talking to the DB.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":299,"context_line":"            if conf is _NOTSET:"},{"line_number":300,"context_line":"                conf \u003d cfg.CONF"},{"line_number":301,"context_line":"            if conf is not None:"},{"line_number":302,"context_line":"                conf.register_opts(options.database_opts, \u0027database\u0027)"},{"line_number":303,"context_line":""},{"line_number":304,"context_line":"            url_args \u003d self._url_args_for_conf(conf)"},{"line_number":305,"context_line":"            if connection:"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_7831dfa1","line":302,"updated":"2014-12-08 12:00:04.000000000","message":"Why not do this in global scope? That\u0027s the usual pattern.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":299,"context_line":"            if conf is _NOTSET:"},{"line_number":300,"context_line":"                conf \u003d cfg.CONF"},{"line_number":301,"context_line":"            if conf is not None:"},{"line_number":302,"context_line":"                conf.register_opts(options.database_opts, \u0027database\u0027)"},{"line_number":303,"context_line":""},{"line_number":304,"context_line":"            url_args \u003d self._url_args_for_conf(conf)"},{"line_number":305,"context_line":"            if connection:"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_223d4c90","line":302,"in_reply_to":"3a961159_7831dfa1","updated":"2014-12-08 23:11:12.000000000","message":"the existing EngineFacade in oslo.db calls register_opts inside of EngineFacade.from_config().  I was attempting to keep the behavior identical as I don\u0027t know what side effects this register_opts() might have.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":332,"context_line":"        return engine, sessionmaker"},{"line_number":333,"context_line":""},{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class _TestTransactionFactory(_TransactionFactory):"},{"line_number":336,"context_line":"    \"\"\"A :class:`._TransactionFactory` used by test suites."},{"line_number":337,"context_line":""},{"line_number":338,"context_line":"    This is a :class:`._TransactionFactory` that can be directly injected"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_986dab07","line":335,"updated":"2014-12-08 12:00:04.000000000","message":"Shouldn\u0027t this live with the tests?","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":332,"context_line":"        return engine, sessionmaker"},{"line_number":333,"context_line":""},{"line_number":334,"context_line":""},{"line_number":335,"context_line":"class _TestTransactionFactory(_TransactionFactory):"},{"line_number":336,"context_line":"    \"\"\"A :class:`._TransactionFactory` used by test suites."},{"line_number":337,"context_line":""},{"line_number":338,"context_line":"    This is a :class:`._TransactionFactory` that can be directly injected"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_82f9a0ca","line":335,"in_reply_to":"3a961159_986dab07","updated":"2014-12-08 23:11:12.000000000","message":"this fixture is here not just for oslo.db\u0027s tests but for the test suite of any project, so needs to be importable.  It could also be in oslo.db.sqlalchemy.test_base which is the current consumer of it, but I didn\u0027t want to limit its use to projects that happen to use that test fixture (though this might be YAGNI also and maybe it should be in there).","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":363,"context_line":"class _TransactionContext(object):"},{"line_number":364,"context_line":"    def __init__(self, instance, context, previous):"},{"line_number":365,"context_line":"        self._previous_ctx \u003d previous"},{"line_number":366,"context_line":"        self.instance \u003d instance"},{"line_number":367,"context_line":"        self.context \u003d context"},{"line_number":368,"context_line":"        self.is_writer \u003d None"},{"line_number":369,"context_line":"        self.session \u003d None"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_739ae015","line":366,"updated":"2014-12-08 12:00:04.000000000","message":"Could we call that factory rather than instance? I found this confusing.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":363,"context_line":"class _TransactionContext(object):"},{"line_number":364,"context_line":"    def __init__(self, instance, context, previous):"},{"line_number":365,"context_line":"        self._previous_ctx \u003d previous"},{"line_number":366,"context_line":"        self.instance \u003d instance"},{"line_number":367,"context_line":"        self.context \u003d context"},{"line_number":368,"context_line":"        self.is_writer \u003d None"},{"line_number":369,"context_line":"        self.session \u003d None"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_e200a4ac","line":366,"in_reply_to":"3a961159_739ae015","updated":"2014-12-08 23:11:12.000000000","message":"ah yes this name should be changed, the object was called \"TransactionInstance\" in an earlier iteration.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":380,"context_line":"        if self._previous_ctx:"},{"line_number":381,"context_line":"            self.context._engine_facade_ctx \u003d self._previous_ctx"},{"line_number":382,"context_line":"            if self._previous_ctx.connection:"},{"line_number":383,"context_line":"                self.context.connection \u003d self._previous_ctx.connection"},{"line_number":384,"context_line":"            if self._previous_ctx.session:"},{"line_number":385,"context_line":"                self.context.session \u003d self._previous_ctx.session"},{"line_number":386,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_1358bc55","line":383,"updated":"2014-12-08 12:00:04.000000000","message":"Given that we\u0027re monkeying around with a foreign object here, I think we need to call this __oslodb_connection or some such. Same for session below. We could be safer still, in fact, and cache these values in our own weakref dict.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":380,"context_line":"        if self._previous_ctx:"},{"line_number":381,"context_line":"            self.context._engine_facade_ctx \u003d self._previous_ctx"},{"line_number":382,"context_line":"            if self._previous_ctx.connection:"},{"line_number":383,"context_line":"                self.context.connection \u003d self._previous_ctx.connection"},{"line_number":384,"context_line":"            if self._previous_ctx.session:"},{"line_number":385,"context_line":"                self.context.session \u003d self._previous_ctx.session"},{"line_number":386,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_02d4d01e","line":383,"in_reply_to":"3a961159_1358bc55","updated":"2014-12-08 23:11:12.000000000","message":"we talked about this on IRC and since the blueprint calls for projects calling upon \"context.session\" and \"context.connection\" i think we are leaving it as is for now, if projects need this to be configurable we can build an extra system to provide for that.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":393,"context_line":"                if self.session is not None:"},{"line_number":394,"context_line":"                    # use existing session, which is outermost"},{"line_number":395,"context_line":"                    self.connection \u003d self.context.connection \u003d \\"},{"line_number":396,"context_line":"                        self.session.connection()"},{"line_number":397,"context_line":"                    yield self.connection"},{"line_number":398,"context_line":"                else:"},{"line_number":399,"context_line":"                    # is outermost"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_c5b4abf4","line":396,"updated":"2014-12-08 12:00:04.000000000","message":"This is an asymmetry: connection within a session maintains the transaction, session within a connection doesn\u0027t.\n\nIs there any way to make this symmetrical? Is it worth it?","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"769af0eb82f7ec4c27b44b7d84ccb8b8e4934ec1","unresolved":false,"context_lines":[{"line_number":393,"context_line":"                if self.session is not None:"},{"line_number":394,"context_line":"                    # use existing session, which is outermost"},{"line_number":395,"context_line":"                    self.connection \u003d self.context.connection \u003d \\"},{"line_number":396,"context_line":"                        self.session.connection()"},{"line_number":397,"context_line":"                    yield self.connection"},{"line_number":398,"context_line":"                else:"},{"line_number":399,"context_line":"                    # is outermost"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_c96a8480","line":396,"in_reply_to":"3a961159_34f28606","updated":"2014-12-11 14:25:16.000000000","message":"\u003e I was wondering if it was possible to create an sqlalchemy session which uses an existing connection. Sounds like the answer\u0027s no.\n\nthere absolutely is, however I\u0027m trying to make the use of the Session alone stick more to idiomatic use patterns; since 90% of the usages of these systems only involve straight session use.\n\n\u003e it would not be obvious to the user/reviewer that they were creating 2 independent connections/transactions,\n\nI\u0027m not sure how that happens here, but the intention of the system is that this absolutely never happens.  there is one connection, one transaction, and that\u0027s it, unless you explicitly call upon the transaction() function to declare a second transaction.\n\n\u003e but calls a function which requires a session, they can request a session and extract the connection from it: context.session.connection().\n\nthat\u0027s what this line of code (line 396) does!  it is calling session.connection() for the case where Session is in play already and context manager requests a connection.    There\u0027s only one Connection object in play with this system, guaranteed, or it\u0027s a bug.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"5f037b71c8f332809c096282825b02d51bcda8ad","unresolved":false,"context_lines":[{"line_number":393,"context_line":"                if self.session is not None:"},{"line_number":394,"context_line":"                    # use existing session, which is outermost"},{"line_number":395,"context_line":"                    self.connection \u003d self.context.connection \u003d \\"},{"line_number":396,"context_line":"                        self.session.connection()"},{"line_number":397,"context_line":"                    yield self.connection"},{"line_number":398,"context_line":"                else:"},{"line_number":399,"context_line":"                    # is outermost"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_34f28606","line":396,"in_reply_to":"3a961159_62b114f8","updated":"2014-12-11 09:52:01.000000000","message":"I was wondering if it was possible to create an sqlalchemy session which uses an existing connection. Sounds like the answer\u0027s no.\n\nI wonder if this is likely to come up... Probably not, tbh, meaning it\u0027s hardly worth spending a lot of time on. If it did, though, I think it would be bad: it would not be obvious to the user/reviewer that they were creating 2 independent connections/transactions, which could lead to subtle bugs.\n\nIt might actually be nicer to die with an Exception, and document a workaround: if anybody does ever write a function which uses a connection, but calls a function which requires a session, they can request a session and extract the connection from it: context.session.connection().","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":393,"context_line":"                if self.session is not None:"},{"line_number":394,"context_line":"                    # use existing session, which is outermost"},{"line_number":395,"context_line":"                    self.connection \u003d self.context.connection \u003d \\"},{"line_number":396,"context_line":"                        self.session.connection()"},{"line_number":397,"context_line":"                    yield self.connection"},{"line_number":398,"context_line":"                else:"},{"line_number":399,"context_line":"                    # is outermost"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_62b114f8","line":396,"in_reply_to":"3a961159_c5b4abf4","updated":"2014-12-08 23:11:12.000000000","message":"this is a little bit of a mindbender for me to see it that way, but I think the source of the \"asymmetry\" here is that a SQLAlchemy ORM Session implies a Connection has already been created, if one was not passed to it; but a SQLAlchemy Core Connection does *not* imply any ORM Session is present.   These are two systems where one is dependent on the other, so within the scope of making it transparent whichever one you started with, i think the asymmetry is intrinsic to that.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":433,"context_line":"            try:"},{"line_number":434,"context_line":"                self.session.begin()"},{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_2592cf57","line":436,"updated":"2014-12-08 12:00:04.000000000","message":"Is there any reason to commit a reader transaction? Or does sqlalchemy magic this away for us if it\u0027s not required?","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":433,"context_line":"            try:"},{"line_number":434,"context_line":"                self.session.begin()"},{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_629f5453","line":436,"in_reply_to":"3a961159_2592cf57","updated":"2014-12-08 23:11:12.000000000","message":"the Python DBAPI has no standard system where there is not a database transaction present in any case, and in the case where we use a Session, a single connection stays open for the scope that we use it.   So there is a transaction, and we have two choices; either roll it back, or commit it.  In my own practice, I actually tend to go for rollback() for a reader, and we might want to do that here.  However I\u0027ve noted that in the world at large folks tend to want to just commit all transactions.   There are performance concerns in some cases either way.    In this case I think the blueprint actually should have posed this question, and I think we should get some input on it from MySQL/PG/galera experts what is most appropriate.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"5f037b71c8f332809c096282825b02d51bcda8ad","unresolved":false,"context_lines":[{"line_number":433,"context_line":"            try:"},{"line_number":434,"context_line":"                self.session.begin()"},{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_f4d55e1c","line":436,"in_reply_to":"3a961159_629f5453","updated":"2014-12-11 09:52:01.000000000","message":"I thought of a reason that it might be better to rollback a read session rather than commit it. In my experiment with the Nova api, my readers didn\u0027t commit. In marking up the db api methods I made several errors marking writer methods as readers. This was quickly obvious in the unit tests, because db updates had no effect. I don\u0027t think we\u0027d be able to catch these errors so quickly if readers also commit.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"f2c03157c786c025a534fae40294f1a341044d42","unresolved":false,"context_lines":[{"line_number":433,"context_line":"            try:"},{"line_number":434,"context_line":"                self.session.begin()"},{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_f62deda9","line":436,"in_reply_to":"3a961159_89b15c49","updated":"2014-12-15 21:57:24.000000000","message":"Done","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"769af0eb82f7ec4c27b44b7d84ccb8b8e4934ec1","unresolved":false,"context_lines":[{"line_number":433,"context_line":"            try:"},{"line_number":434,"context_line":"                self.session.begin()"},{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_89b15c49","line":436,"in_reply_to":"3a961159_f4d55e1c","updated":"2014-12-11 14:25:16.000000000","message":"that\u0027s a great idea.  I\u0027ll make readers do a rollback().\n\nof course it can be configurable but I\u0027d rather wait until someone has a rationale for that need.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d1fb4f1fefac5429c022f653f3032bb9ca0df0ea","unresolved":false,"context_lines":[{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"},{"line_number":440,"context_line":"            finally:"},{"line_number":441,"context_line":"                self.session.close()"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_0596b394","line":438,"updated":"2014-12-08 12:00:04.000000000","message":"I think you want to use save_and_reraise_exception from oslo.utils here because of interaction with eventlet. If another thread is scheduled during rollback(), it could clear the exception context before you raise it. \n\nLooks like there are bare \u0027raise\u0027s in other places, too. I\u0027m not going to annotate them all, but I think they all need to be updated.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42f8b640b25a3abd11d97ef26886302daad111cd","unresolved":false,"context_lines":[{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"},{"line_number":440,"context_line":"            finally:"},{"line_number":441,"context_line":"                self.session.close()"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_a2a05c91","line":438,"in_reply_to":"3a961159_0596b394","updated":"2014-12-08 23:11:12.000000000","message":"Yah im surprised a hacking rule isnt catching those.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"f2c03157c786c025a534fae40294f1a341044d42","unresolved":false,"context_lines":[{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"},{"line_number":440,"context_line":"            finally:"},{"line_number":441,"context_line":"                self.session.close()"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_89f72ef5","line":438,"in_reply_to":"3a961159_1cbb21c5","updated":"2014-12-15 21:57:24.000000000","message":"adding a comment to both raises to get some opinions.  we are calling raw \"raise\" in exc_filters.","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"d3ab48d757ecdc97fd664451be9f4e51d9af351b","unresolved":false,"context_lines":[{"line_number":435,"context_line":"                yield self.session"},{"line_number":436,"context_line":"                self.session.commit()"},{"line_number":437,"context_line":"            except Exception:"},{"line_number":438,"context_line":"                self.session.rollback()"},{"line_number":439,"context_line":"                raise"},{"line_number":440,"context_line":"            finally:"},{"line_number":441,"context_line":"                self.session.close()"}],"source_content_type":"text/x-python","patch_set":11,"id":"3a961159_1cbb21c5","line":438,"in_reply_to":"3a961159_a2a05c91","updated":"2014-12-10 08:01:33.000000000","message":"I don\u0027t think this is a problem anymore with newer eventlets/greenlets.\n\nLikely save_and_reraise isn\u0027t needed anymore (although its a useful context manager on its own imho anyway...)\n\nI think this was fixed in https://bitbucket.org/eventlet/eventlet/issue/129/exception-info-clearing-is-problematic-and (or a similar one...)\n\nAlso similar @ https://bugzilla.redhat.com/show_bug.cgi?id\u003d1061329\n\nI\u0027m thinking said interaction is hopefully a non-issue anymore...","commit_id":"42282032bd4958b363e3a561203aac2d35d9b629"}],"oslo_db/exception.py":[{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    \"\"\""},{"line_number":174,"context_line":""},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"class OsloDBNotSupportedWarning(Warning):"},{"line_number":177,"context_line":"    \"\"\"Warn that an argument or call that was passed is not supported.\"\"\""},{"line_number":178,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_b607e51d","line":175,"updated":"2015-01-19 16:01:06.000000000","message":"Hmm, what is the point of creating subclasses here instead of using Warning and DeprecationWarning directly?","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"218da0aa3bc9d9f4cec18183aa75f65c0aedf581","unresolved":false,"context_lines":[{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    \"\"\""},{"line_number":174,"context_line":""},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"class OsloDBNotSupportedWarning(Warning):"},{"line_number":177,"context_line":"    \"\"\"Warn that an argument or call that was passed is not supported.\"\"\""},{"line_number":178,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_a2ff9f65","line":175,"in_reply_to":"3a961159_b607e51d","updated":"2015-01-19 17:31:13.000000000","message":"it allows one to filter for them directly:\n\nhttps://docs.python.org/2/library/warnings.html\n\n    warnings.simplefilter(\"error\", OsloDBDeprecationWarning)","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a0adc18bf37a321081a2a7ca2c637bb21641a5ba","unresolved":false,"context_lines":[{"line_number":173,"context_line":"    \"\"\""},{"line_number":174,"context_line":""},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"class OsloDBNotSupportedWarning(Warning):"},{"line_number":177,"context_line":"    \"\"\"Warn that an argument or call that was passed is not supported.\"\"\""},{"line_number":178,"context_line":""},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_496d8902","line":176,"updated":"2015-01-16 02:39:48.000000000","message":"Just noticed this... you should leave off the \"OsloDB\" prefix on these exception class names I think, since none of the other exceptions in this file begin with that.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"218da0aa3bc9d9f4cec18183aa75f65c0aedf581","unresolved":false,"context_lines":[{"line_number":173,"context_line":"    \"\"\""},{"line_number":174,"context_line":""},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"class OsloDBNotSupportedWarning(Warning):"},{"line_number":177,"context_line":"    \"\"\"Warn that an argument or call that was passed is not supported.\"\"\""},{"line_number":178,"context_line":""},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_6213f7b7","line":176,"in_reply_to":"3a961159_496d8902","updated":"2015-01-19 17:31:13.000000000","message":"the OsloDB prefix is so their names aren\u0027t confused with DeprecationWarning, which is a Python builtin.    It\u0027s not ideal to replace the builtin DeprecationWarning in the module space here with a different class of the same name.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":173,"context_line":"    \"\"\""},{"line_number":174,"context_line":""},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"class OsloDBNotSupportedWarning(Warning):"},{"line_number":177,"context_line":"    \"\"\"Warn that an argument or call that was passed is not supported.\"\"\""},{"line_number":178,"context_line":""},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_3eb74723","line":176,"in_reply_to":"3a961159_6213f7b7","updated":"2015-01-19 18:38:30.000000000","message":"I\u0027ve changed OsloDBNotSupportedWarning to NotSupportedWarning.  Not sure about DeprecationWarning though, SQLAlchemy itself has SADeprecationWarning, SAPendingDeprecationWarning, etc.   We might say \"from __builtins__ import DeprecationWarning as _DeprecationWarning\" but that isn\u0027t py3k compat and six doesn\u0027t have any pattern for this.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"}],"oslo_db/sqlalchemy/enginefacade.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a15969d9162460d8a2f71381d5c8c74527f2ba42","unresolved":false,"context_lines":[{"line_number":35,"context_line":"    :class:`._TestTransactionFactory` subclass used by the oslo.db test suite."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    The module-level facade functions writer(), reader()"},{"line_number":38,"context_line":"    within enginefacdade by default make use of the global instance of"},{"line_number":39,"context_line":"    :class:`._TransactionFactory`."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":13,"id":"3a961159_4c78f48f","line":38,"updated":"2014-12-15 22:45:22.000000000","message":"s/enginefacdade/enginefacade/ :)","commit_id":"845852167dbd7a97d5e8735e22f727a284206c89"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"6a553caf864a294501d899c52b28c98d22fdf5a8","unresolved":false,"context_lines":[{"line_number":35,"context_line":"    :class:`._TestTransactionFactory` subclass used by the oslo.db test suite."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    The module-level facade functions writer(), reader()"},{"line_number":38,"context_line":"    within enginefacdade by default make use of the global instance of"},{"line_number":39,"context_line":"    :class:`._TransactionFactory`."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":13,"id":"3a961159_87d0f5ca","line":38,"in_reply_to":"3a961159_4c78f48f","updated":"2015-01-05 16:12:58.000000000","message":"Done","commit_id":"845852167dbd7a97d5e8735e22f727a284206c89"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"d8215af5dbb8ff49242ad37da8b6efc95b6352e9","unresolved":false,"context_lines":[{"line_number":459,"context_line":"                # (and one six.reraise())."},{"line_number":460,"context_line":"                raise"},{"line_number":461,"context_line":"            finally:"},{"line_number":462,"context_line":"                self.session.close()"},{"line_number":463,"context_line":"                self.session \u003d None"},{"line_number":464,"context_line":"                del self.context.session"},{"line_number":465,"context_line":"                if outermost:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_21f8a3c3","line":462,"updated":"2015-01-05 13:38:15.000000000","message":"I think this is the right thing to do, but I\u0027d like to point out a knock-on. There are places in Nova which currently rely on lazily loading an attribute:\n\napi.py:\n@enginefacade.reader\ndef get_foo(context):\n     return model_query(context, ...)\n\nnova_thingy.py:\ndef no_db_func(context):\n    foo \u003d get_foo(context)\n    return foo[\u0027attr_which_isnt_loaded\u0027]\n\nWhen we didn\u0027t close the session the above worked. When we close the session the object becomes detached and it throws an exception. I don\u0027t think you were doing this in earlier versions of the patch (haven\u0027t checked, though).\n\nHere\u0027s a concrete example from a test:\n\nhttps://review.openstack.org/#/c/136408/\n\nI can\u0027t point to a specific example right now which isn\u0027t in a test because I haven\u0027t got that far yet. However, I did this in my toy transaction scoping code and I recall hitting a few. The tests do it a *lot* iirc.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"c99be38f29fa1b5f1425b725eeff8f9b8d5dea89","unresolved":false,"context_lines":[{"line_number":459,"context_line":"                # (and one six.reraise())."},{"line_number":460,"context_line":"                raise"},{"line_number":461,"context_line":"            finally:"},{"line_number":462,"context_line":"                self.session.close()"},{"line_number":463,"context_line":"                self.session \u003d None"},{"line_number":464,"context_line":"                del self.context.session"},{"line_number":465,"context_line":"                if outermost:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_da8184fc","line":462,"in_reply_to":"3a961159_21f8a3c3","updated":"2015-01-05 15:21:00.000000000","message":"See below: session.rollback() before responding to this.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a007c613d187489bc6256da88e7be4160095655f","unresolved":false,"context_lines":[{"line_number":459,"context_line":"                # (and one six.reraise())."},{"line_number":460,"context_line":"                raise"},{"line_number":461,"context_line":"            finally:"},{"line_number":462,"context_line":"                self.session.close()"},{"line_number":463,"context_line":"                self.session \u003d None"},{"line_number":464,"context_line":"                del self.context.session"},{"line_number":465,"context_line":"                if outermost:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_3558d956","line":462,"in_reply_to":"3a961159_21f8a3c3","updated":"2015-01-05 16:12:29.000000000","message":"i think this is what you got into in that email thread on openstack dev.   this is not a pattern we should be using casually.  sessions should absolutely be closed when the scope of the transaction is decided to be over. if nova is returning objects outside the transaction, and then a non-DB function is calling upon lazyload attributes, that *opens a new transaction*.  this is exactly the kind of sloppiness we\u0027re trying to fix. I believe that in Nova, if a non-DB method needs to call into a DB method that returns a live object which requires lazyloading, then as I\u0027ve mentioned before we need more decorators in Nova that will in fact expand the transaction to surround the \"non DB\" method as well, in a transparent way that does not expose this detail.  that is, the \"db\" api that it\u0027s calling into needs to expose a decorator or context manager of its own.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"6b7305c125d01f32478649ffbe73be2da5a4d201","unresolved":false,"context_lines":[{"line_number":459,"context_line":"                # (and one six.reraise())."},{"line_number":460,"context_line":"                raise"},{"line_number":461,"context_line":"            finally:"},{"line_number":462,"context_line":"                self.session.close()"},{"line_number":463,"context_line":"                self.session \u003d None"},{"line_number":464,"context_line":"                del self.context.session"},{"line_number":465,"context_line":"                if outermost:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_4be6a845","line":462,"in_reply_to":"3a961159_3558d956","updated":"2015-01-05 16:52:21.000000000","message":"This is subtly different to the issue below, and I\u0027m happy to treat these as bugs in Nova as they pop up. I\u0027m happy with the principal that nothing should be touching the db outside the explicit scope of a transaction.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"c99be38f29fa1b5f1425b725eeff8f9b8d5dea89","unresolved":false,"context_lines":[{"line_number":472,"context_line":"        if self.is_writer:"},{"line_number":473,"context_line":"            session.commit()"},{"line_number":474,"context_line":"        else:"},{"line_number":475,"context_line":"            session.rollback()"},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"    def _end_connection_transaction(self, transaction):"},{"line_number":478,"context_line":"        if self.is_writer:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_daaa6484","line":475,"updated":"2015-01-05 15:21:00.000000000","message":"This has an undesirable side-effect. In rolling back the transaction, sqlalchemy eventually does SessionTransaction._restore_snapshot(), which deletes the instance state. This means that you can\u0027t return an object and read *any* state outside the transaction, even stuff you already fetched. The only way round this I\u0027ve found so far is to explicitly expunge objects you want to return. This seems untidy.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"6b7305c125d01f32478649ffbe73be2da5a4d201","unresolved":false,"context_lines":[{"line_number":472,"context_line":"        if self.is_writer:"},{"line_number":473,"context_line":"            session.commit()"},{"line_number":474,"context_line":"        else:"},{"line_number":475,"context_line":"            session.rollback()"},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"    def _end_connection_transaction(self, transaction):"},{"line_number":478,"context_line":"        if self.is_writer:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_d043236a","line":475,"in_reply_to":"3a961159_55fba546","updated":"2015-01-05 16:52:21.000000000","message":"As I hope I made clear before, I agree with you completely on this.\n\nHowever, we need a path to get there, and Nova does this *literally everywhere* the db is used. If we can\u0027t update db api call sites independently, I am concerned that any patch will be so large and invasive it will be unmergeable in practise. Apart from being a review nightmare, it would die under the weight of merge conflicts. We\u0027re going to need to drip these in in small chunks, with a view to eliminating them eventually. This means that we need to be able to produce detached objects in the interim.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"68b59681b8537691e2a011c4e2dfc0728510d152","unresolved":false,"context_lines":[{"line_number":472,"context_line":"        if self.is_writer:"},{"line_number":473,"context_line":"            session.commit()"},{"line_number":474,"context_line":"        else:"},{"line_number":475,"context_line":"            session.rollback()"},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"    def _end_connection_transaction(self, transaction):"},{"line_number":478,"context_line":"        if self.is_writer:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_6bec44bc","line":475,"in_reply_to":"3a961159_d043236a","updated":"2015-01-05 17:05:10.000000000","message":"So I guess your concern is that adding \"boxing\" to all non-db operations as well  would be just too large of a patch, that may be true, i need to look into the specifics.  there might be a way to add some kind of wrapping, or even instrumentation, at an even higher level such that the impact on source code is not significant.\n\nAlso it\u0027s not clear to me if we\u0027re looking for detached objects, or objects that are still implicitly attached.  The other case above seems to indicate a lazy load operation is still needed.    Working with detached objects outside of the transaction block would be much preferable to leaking out attached objects that continue to start new transactions.   which one of these cases is the one that you feel we cannot change immediately?","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a007c613d187489bc6256da88e7be4160095655f","unresolved":false,"context_lines":[{"line_number":472,"context_line":"        if self.is_writer:"},{"line_number":473,"context_line":"            session.commit()"},{"line_number":474,"context_line":"        else:"},{"line_number":475,"context_line":"            session.rollback()"},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"    def _end_connection_transaction(self, transaction):"},{"line_number":478,"context_line":"        if self.is_writer:"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_55fba546","line":475,"in_reply_to":"3a961159_daaa6484","updated":"2015-01-05 16:12:29.000000000","message":"IMO the objects that are used within the transaction block should not be used *outside* of that block; this is known as using the objects in a detached state.  If we wanted that, we\u0027d just call session.close() here, which does what you describe.  however the objects in a detached state no longer represent any row in the system and any unloaded attributes will not be loadable. it\u0027s not a use case I think this system should support.   my talk at http://www.sqlalchemy.org/library.html#thesqlalchemysessionindepth goes into the rationale for this.\n\nif an app truly needs to use the objects in a detached state, we can always make this call .close() instead, which I\u0027d prefer as a configurable option.  But i don\u0027t think it\u0027s a current use case.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"ba3bcfd2fe802e81129ec0afaf6d9d0dd6517f74","unresolved":false,"context_lines":[{"line_number":778,"context_line":"            exception.OsloDBDeprecationWarning,"},{"line_number":779,"context_line":"            stacklevel\u003d2)"},{"line_number":780,"context_line":""},{"line_number":781,"context_line":"        self._factory \u003d _TransactionFactory()"},{"line_number":782,"context_line":""},{"line_number":783,"context_line":"        self._factory.configure("},{"line_number":784,"context_line":"            sqlite_fk\u003dsqlite_fk,"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a961159_3440e234","line":781,"updated":"2015-01-05 11:59:04.000000000","message":"This is a problem for Nova tests which use SQLite. The issue is that as soon as we migrate some functions to the new API, we\u0027re now creating 2 independent in memory SQLite databases.\n\nI realise this is only a problem for SQLite, but without a solution we can\u0027t implement this incrementally. I don\u0027t think that rewriting all the Nova tests to not use SQLite is a viable option.\n\nI\u0027ve hacked this locally by changing the above to self._factory \u003d _factory (i.e. using the global factory). This is untidy, and I strongly suspect it\u0027s also incorrect due to differing configuration, and possibly other reasons. We need a solution for this, though.\n\nIf it\u0027s cleaner, I\u0027d also be happy to add a hack to the Nova tests to work round this rather than clutter up the library. However, in that case it could still do with a doc in LegacyEngineFacade.","commit_id":"feed9db7780d6d7af889e3da66244414aabf0153"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"67cd33efb8854843d3d345075b09165424207978","unresolved":false,"context_lines":[{"line_number":412,"context_line":"        self.rollback_reader_sessions \u003d rollback_reader_sessions"},{"line_number":413,"context_line":""},{"line_number":414,"context_line":"    def _attach(self):"},{"line_number":415,"context_line":"        self.context._engine_facade_ctx \u003d self"},{"line_number":416,"context_line":"        self._attached \u003d True"},{"line_number":417,"context_line":""},{"line_number":418,"context_line":"    def _detach(self):"}],"source_content_type":"text/x-python","patch_set":19,"id":"3a961159_b7648ab3","line":415,"updated":"2015-01-07 14:33:01.000000000","message":"We discussed this before: I was non-specifically worried about adding attributes to an arbitrary object, but given that the given object is \u0027friendly\u0027 and the syntax is much nicer, we agreed that this is a good way to go.\n\nI\u0027ve hit a tricky problem, though: a session isn\u0027t deepcopy()able. Nova deepcopy()s the context object when creating an elevated context. This means that context.elevated() called within a TransactionContext now fails.\n\nPossible solutions:\n\n* Update Nova\u0027s RequestContext.elevated() to be aware of it. Risk this also happening elsewhere.\n\n* Something evil involving a custom pickler and a global registry of TransactionContext objects.\n\n* Use one of the alternate mechanisms for propagating transaction context in Nova.\n\n* Add _engine_facade_ctx and session as properties to the class of the given object which pull their data from a global weak dict.\n\nNone of these are without flaws. Thoughts?","commit_id":"c8d4a4a144746748ac7a521f7000baeec0e4ce2e"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"e2f733a33cd677a632ef02c80e5f74d17f36b15c","unresolved":false,"context_lines":[{"line_number":412,"context_line":"        self.rollback_reader_sessions \u003d rollback_reader_sessions"},{"line_number":413,"context_line":""},{"line_number":414,"context_line":"    def _attach(self):"},{"line_number":415,"context_line":"        self.context._engine_facade_ctx \u003d self"},{"line_number":416,"context_line":"        self._attached \u003d True"},{"line_number":417,"context_line":""},{"line_number":418,"context_line":"    def _detach(self):"}],"source_content_type":"text/x-python","patch_set":19,"id":"3a961159_49d2e9d1","line":415,"in_reply_to":"3a961159_b7648ab3","updated":"2015-01-07 18:10:34.000000000","message":"oslo.db is handing out a subclass of Session, we can provide `__deepcopy__` on it.   we also hand out Connection subclasses, though not under all circumstances, but that can be changed too.\n\nHowever, this is kludgy.  I think deepcopy() is more or less pretty evil, it\u0027s implicit everything all the way.  What elements need to be copied specifically in nova\u0027s context?    I\u0027d favor these elements being named explicitly.","commit_id":"c8d4a4a144746748ac7a521f7000baeec0e4ce2e"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":15,"context_line":"import contextlib"},{"line_number":16,"context_line":"import copy"},{"line_number":17,"context_line":"import functools"},{"line_number":18,"context_line":"from six.moves import _thread as thread"},{"line_number":19,"context_line":"import threading"},{"line_number":20,"context_line":"import warnings"},{"line_number":21,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_ec2fe087","line":18,"updated":"2015-01-19 16:01:06.000000000","message":"nit: I wonder, if we should just use threading.current_thread().ident below","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":15,"context_line":"import contextlib"},{"line_number":16,"context_line":"import copy"},{"line_number":17,"context_line":"import functools"},{"line_number":18,"context_line":"from six.moves import _thread as thread"},{"line_number":19,"context_line":"import threading"},{"line_number":20,"context_line":"import warnings"},{"line_number":21,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_fec69f68","line":18,"in_reply_to":"3a961159_22a64fac","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"218da0aa3bc9d9f4cec18183aa75f65c0aedf581","unresolved":false,"context_lines":[{"line_number":15,"context_line":"import contextlib"},{"line_number":16,"context_line":"import copy"},{"line_number":17,"context_line":"import functools"},{"line_number":18,"context_line":"from six.moves import _thread as thread"},{"line_number":19,"context_line":"import threading"},{"line_number":20,"context_line":"import warnings"},{"line_number":21,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_22a64fac","line":18,"in_reply_to":"3a961159_ec2fe087","updated":"2015-01-19 17:31:13.000000000","message":"I was concerned about performance but took a look at the source and it\u0027s fine.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a0adc18bf37a321081a2a7ca2c637bb21641a5ba","unresolved":false,"context_lines":[{"line_number":26,"context_line":"from oslo_db.sqlalchemy import engines"},{"line_number":27,"context_line":"from oslo_db.sqlalchemy import orm"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"_NOTSET \u003d object()"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class _TransactionFactory(object):"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_8907711c","line":29,"updated":"2015-01-16 02:39:48.000000000","message":"What\u0027s the idea here behind using object() versus just None? Is there a tricky piece of Python internals that you\u0027re working around here or something?","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":26,"context_line":"from oslo_db.sqlalchemy import engines"},{"line_number":27,"context_line":"from oslo_db.sqlalchemy import orm"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"_NOTSET \u003d object()"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"class _TransactionFactory(object):"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_913a3332","line":29,"in_reply_to":"3a961159_8907711c","updated":"2015-01-16 04:31:18.000000000","message":"well it\u0027s just to distinguish between a key that was not sent at all from the outside in the various _xyz_cfg dictionaries, vs. one that was actually sent in w/ None.  Like if I wanted to send \"None\" for \"mysql_sql_mode\".   I\u0027m not sure any of these keys would realistically want None at the moment, but i like that the system supports sending a None in as a means to override a default vs. NOTSET means don\u0027t override the default.   I have to do this in SQLAlchemy / alembic / dogpile a lot.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            \u0027rollback_reader_sessions\u0027: False"},{"line_number":66,"context_line":"        }"},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"        # options that are defined in oslo.db.options.database_opts,"},{"line_number":69,"context_line":"        # but appear to have no use.  Should these be removed from"},{"line_number":70,"context_line":"        # oslo.db.options ?"},{"line_number":71,"context_line":"        self._ignored_cfg \u003d dict("}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_295abaf5","line":68,"updated":"2015-01-19 16:01:06.000000000","message":"We use them here: https://github.com/openstack/oslo.db/blob/master/oslo_db/api.py#L123-L229","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"218da0aa3bc9d9f4cec18183aa75f65c0aedf581","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            \u0027rollback_reader_sessions\u0027: False"},{"line_number":66,"context_line":"        }"},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"        # options that are defined in oslo.db.options.database_opts,"},{"line_number":69,"context_line":"        # but appear to have no use.  Should these be removed from"},{"line_number":70,"context_line":"        # oslo.db.options ?"},{"line_number":71,"context_line":"        self._ignored_cfg \u003d dict("}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_c2c90b7c","line":68,"in_reply_to":"3a961159_295abaf5","updated":"2015-01-19 17:31:13.000000000","message":"how about min_pool_size and sqlite_db ?","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a0adc18bf37a321081a2a7ca2c637bb21641a5ba","unresolved":false,"context_lines":[{"line_number":271,"context_line":"class _TransactionContext(object):"},{"line_number":272,"context_line":"    \"\"\"Represent a single database transaction in progress.\"\"\""},{"line_number":273,"context_line":""},{"line_number":274,"context_line":"    def __init__(self, factory, rollback_reader_sessions\u003dFalse):"},{"line_number":275,"context_line":"        self.factory \u003d factory"},{"line_number":276,"context_line":"        self.is_writer \u003d None"},{"line_number":277,"context_line":"        self.session \u003d None"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_9b35f4dc","line":274,"updated":"2015-01-16 02:39:48.000000000","message":"Would be a good idea to docstring the purpose/intent of the rollback_reader_session parameter here.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":271,"context_line":"class _TransactionContext(object):"},{"line_number":272,"context_line":"    \"\"\"Represent a single database transaction in progress.\"\"\""},{"line_number":273,"context_line":""},{"line_number":274,"context_line":"    def __init__(self, factory, rollback_reader_sessions\u003dFalse):"},{"line_number":275,"context_line":"        self.factory \u003d factory"},{"line_number":276,"context_line":"        self.is_writer \u003d None"},{"line_number":277,"context_line":"        self.session \u003d None"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_be0df791","line":274,"in_reply_to":"3a961159_299d5a6d","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":271,"context_line":"class _TransactionContext(object):"},{"line_number":272,"context_line":"    \"\"\"Represent a single database transaction in progress.\"\"\""},{"line_number":273,"context_line":""},{"line_number":274,"context_line":"    def __init__(self, factory, rollback_reader_sessions\u003dFalse):"},{"line_number":275,"context_line":"        self.factory \u003d factory"},{"line_number":276,"context_line":"        self.is_writer \u003d None"},{"line_number":277,"context_line":"        self.session \u003d None"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_b11c8fc3","line":274,"in_reply_to":"3a961159_9b35f4dc","updated":"2015-01-16 04:31:18.000000000","message":"yeah, it\u0027s an option we\u0027ll probably never use it\u0027s just how this was when I first did it; when the context ends, call session.rollback().  But we don\u0027t really want to do that since nova and probably all other apps we want to pass out the objects from the function with their values intact, just detached from a session (session.rollback() wipes out all the data in the objects).    just calling session.close() releases the connection to the pool, which calls connection.rollback() anyway, but without blowing away the state in all the mapped objects.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":271,"context_line":"class _TransactionContext(object):"},{"line_number":272,"context_line":"    \"\"\"Represent a single database transaction in progress.\"\"\""},{"line_number":273,"context_line":""},{"line_number":274,"context_line":"    def __init__(self, factory, rollback_reader_sessions\u003dFalse):"},{"line_number":275,"context_line":"        self.factory \u003d factory"},{"line_number":276,"context_line":"        self.is_writer \u003d None"},{"line_number":277,"context_line":"        self.session \u003d None"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_299d5a6d","line":274,"in_reply_to":"3a961159_b11c8fc3","updated":"2015-01-19 16:01:06.000000000","message":"let\u0027s document that ;)","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":570,"context_line":"        if not hasattr(context, \u0027_facade_scope_tracker\u0027):"},{"line_number":571,"context_line":"            context._facade_scope_tracker \u003d _FacadeScopeTracker(self)"},{"line_number":572,"context_line":"            context._facade_thread_ident \u003d thread_ident"},{"line_number":573,"context_line":"        elif thread_ident !\u003d context._facade_thread_ident:"},{"line_number":574,"context_line":"            # \"copy\" means we are passing a context object into a decorated"},{"line_number":575,"context_line":"            # function; if new thread, we copy the context so that"},{"line_number":576,"context_line":"            # context.session / context.connection aren\u0027t shared from"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_914f93bd","line":573,"updated":"2015-01-16 04:31:18.000000000","message":"so, I\u0027d hate if Nova is not only sending context into a new thread, but then if the newly spawned thread is actually saying \"context.some_data \u003d \u0027done!\u0027\", e.g. setting directly on the context as opposed to mutating something on it, which then needs to be read by the parent.   that actually would be broken by this, because the spawned thread has a deepcopy() of the context now.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":570,"context_line":"        if not hasattr(context, \u0027_facade_scope_tracker\u0027):"},{"line_number":571,"context_line":"            context._facade_scope_tracker \u003d _FacadeScopeTracker(self)"},{"line_number":572,"context_line":"            context._facade_thread_ident \u003d thread_ident"},{"line_number":573,"context_line":"        elif thread_ident !\u003d context._facade_thread_ident:"},{"line_number":574,"context_line":"            # \"copy\" means we are passing a context object into a decorated"},{"line_number":575,"context_line":"            # function; if new thread, we copy the context so that"},{"line_number":576,"context_line":"            # context.session / context.connection aren\u0027t shared from"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_21e3aa35","line":573,"in_reply_to":"3a961159_1b7735d5","updated":"2015-01-19 18:38:30.000000000","message":"Done - I\u0027ve implemented a check for __OSLO_COPY_OK__ for now.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"74b19e67d2dae2574e0c87af3f5d3c588f00b43e","unresolved":false,"context_lines":[{"line_number":570,"context_line":"        if not hasattr(context, \u0027_facade_scope_tracker\u0027):"},{"line_number":571,"context_line":"            context._facade_scope_tracker \u003d _FacadeScopeTracker(self)"},{"line_number":572,"context_line":"            context._facade_thread_ident \u003d thread_ident"},{"line_number":573,"context_line":"        elif thread_ident !\u003d context._facade_thread_ident:"},{"line_number":574,"context_line":"            # \"copy\" means we are passing a context object into a decorated"},{"line_number":575,"context_line":"            # function; if new thread, we copy the context so that"},{"line_number":576,"context_line":"            # context.session / context.connection aren\u0027t shared from"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_9be9651c","line":573,"in_reply_to":"3a961159_914f93bd","updated":"2015-01-16 13:40:19.000000000","message":"I\u0027m don\u0027t think Nova does this anywhere. However, I\u0027m uncomfortable with the idea of implicitly copying the context object here. Here be dragons.\n\nI had thought that we might be better off with a Proxy object here, which we could use to control the copy behaviour. As I thought through it, though, I just came up with a different set of gotchas. Ultimately, I think we\u0027re at risk of tying ourselves in knots trying to ensure that our implicit behaviour doesn\u0027t surprise anybody who isn\u0027t expecting it.\n\nHere\u0027s a thought: why not make it explicit? How about some boilerplate which we add to Nova\u0027s RequestContext, and the decorator expects it to exist.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"8152716654d249f570d349ab47f2ac200b307fa8","unresolved":false,"context_lines":[{"line_number":570,"context_line":"        if not hasattr(context, \u0027_facade_scope_tracker\u0027):"},{"line_number":571,"context_line":"            context._facade_scope_tracker \u003d _FacadeScopeTracker(self)"},{"line_number":572,"context_line":"            context._facade_thread_ident \u003d thread_ident"},{"line_number":573,"context_line":"        elif thread_ident !\u003d context._facade_thread_ident:"},{"line_number":574,"context_line":"            # \"copy\" means we are passing a context object into a decorated"},{"line_number":575,"context_line":"            # function; if new thread, we copy the context so that"},{"line_number":576,"context_line":"            # context.session / context.connection aren\u0027t shared from"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_1b7735d5","line":573,"in_reply_to":"3a961159_9be9651c","updated":"2015-01-16 18:58:22.000000000","message":"So I\u0027m not sure which kind of \"boilerplate\" we\u0027re talking about: if we mean, \"a flag that says its OK to copy me\", that\u0027s one thing, or if we mean, \"magic .session and .connection descriptors that proxy access across threads which are probably part of some OsloDbSQLAlchemyContext mixin\", that\u0027s another.\n\nRegarding the latter approach, i mentioned this in an email I wrote to you yesterday.  if we want a context that implements a special interface or system, Nova and others would either need to leak this detail into their base context objects, or otherwise use a factory-style creational pattern that hides this detail until instantiation time.\n\nOr an alternative is that the Session and Connection members we stick onto the context are themselves proxy objects, like SQLAlchemy\u0027s scoped_session.\n\nBoth of these approaches concern me on multiple fronts.  The explicit context mixin would be a dramatic requirement to add to all openstack projects.   But for both approaches,  this is a lot of complexity to introduce in service of a use case that is very uncommon.\n\nSo I\u0027m hoping we can stick with the idea that if you want to pass your context to a new thread, it has to be copied, either by you or by oslo.  \n\nIf we want to make the copy step the responsibility of the caller, that\u0027s a little tricky but doable, we take the deepcopy() out here, and raise an exception when we do this thread_ident check if the object is detected as being used in a new thread.  We\u0027d probably have to make _facade_thread_ident itself into a more elaborate object that does the right thing when its own __deepcopy__ is called, such that when the object is actually copied, it returns an object that is receptive to a new thread ident.\n\nOr, we keep doing the deepcopy() ourselves here, if what you meant by \"boilerplate\" is a flag like \"__OSLO_COPY_OK__ \u003d True\", then that would be fine!   I can just throw that right in :).  But i don\u0027t know that this decreases risk so much; someone will put the flag there someday, and nobody will ever really know what it means.\n\nI sort of like the idea of a library that wants to send context into a new thread has to call deepcopy() on it, or otherwise produce a new context object that was not yet seen by oslo.db.  that leaves it more in the caller\u0027s court how to deal with it, but definitely forces them to handle it correctly.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"bda713c7a2c80b36576a5c60d67ae06854fca0ed","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import threading"},{"line_number":19,"context_line":"import warnings"},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"from oslo.config import cfg"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"from oslo_db import exception"},{"line_number":24,"context_line":"from oslo_db import options"}],"source_content_type":"text/x-python","patch_set":28,"id":"3a961159_6bad6f9b","line":21,"updated":"2015-01-20 15:54:30.000000000","message":"I\u0027m not sure, that we want it. Can we work with paced CONF data, which comes from outside, instead of work with this cfg.CONG singleton?","commit_id":"35859818c49d093d6cc81c145ab31e864733c6f4"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"6e5686337d2ab206289f2859c550c5a089af99ef","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import threading"},{"line_number":19,"context_line":"import warnings"},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"from oslo.config import cfg"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"from oslo_db import exception"},{"line_number":24,"context_line":"from oslo_db import options"}],"source_content_type":"text/x-python","patch_set":28,"id":"1a930d6b_4ecab3a2","line":21,"in_reply_to":"3a961159_6bad6f9b","updated":"2015-01-20 20:20:24.000000000","message":"So, the proposed and approved spec says that no use of CONF should be needed on the outside:\n\nhttps://review.openstack.org/gitweb?p\u003dopenstack/oslo-specs.git;a\u003dblob;f\u003dspecs/kilo/make-enginefacade-a-facade.rst;h\u003d089f26bb0bd57db8c1a98c05842a2d14be4a0e60;hb\u003dec52f4370bffab5bb93bf90312e2227f415e79ed#l340\n\none can say:\n\n    from oslo.db import enginefacade as sql\n\nand you\u0027re ready to go:\n\n    @sql.reader()\n    def some_function(..):\n\nthere\u0027s an optional configure step, for extra options:\n\n    sql.configure(sqlite_fk\u003dTrue)\n\nbut that\u0027s it!   The import of enginefacade replaces the \"oslo.config\" import we see in places like nova/sqlalchemy/api.py.   Although the most recent nova api.py seems to be adding a cfg option so they\u0027d have to be importing it anyway.\n\nShall we change the usage contract here or is there some other way an import of enginefacade can get at cfg.CONF ?  Why wasn\u0027t this brought up on the blueprint ?   I don\u0027t care either way but at this point I\u0027m really trying to get this thing out the door without further holdups.","commit_id":"35859818c49d093d6cc81c145ab31e864733c6f4"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"bda713c7a2c80b36576a5c60d67ae06854fca0ed","unresolved":false,"context_lines":[{"line_number":571,"context_line":"    def _decorate_for_context(self, fn, ctx_callable):"},{"line_number":572,"context_line":"        @functools.wraps(fn)"},{"line_number":573,"context_line":"        def wrapper(*args, **kwargs):"},{"line_number":574,"context_line":"            context \u003d args[0]"},{"line_number":575,"context_line":"            new_context, facade_tracker \u003d \\"},{"line_number":576,"context_line":"                self._get_facade_scope_tracker_w_copy(context)"},{"line_number":577,"context_line":"            with facade_tracker.transaction_scope() as trans_ctx:"}],"source_content_type":"text/x-python","patch_set":28,"id":"3a961159_68d3b5d5","line":574,"updated":"2015-01-20 15:54:30.000000000","message":"well, so based on this we should suppose, that DB-API method always get context as the first argument. This is true for Nova, Glance, Heat, etc. But there are some openstack projects, which doesn\u0027t work with context in their db-api methods (which can be fixed easily?) and projects, with realised there method as class methods, so they will have `self` as args[0] - see for example Ironic.","commit_id":"35859818c49d093d6cc81c145ab31e864733c6f4"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"6e5686337d2ab206289f2859c550c5a089af99ef","unresolved":false,"context_lines":[{"line_number":571,"context_line":"    def _decorate_for_context(self, fn, ctx_callable):"},{"line_number":572,"context_line":"        @functools.wraps(fn)"},{"line_number":573,"context_line":"        def wrapper(*args, **kwargs):"},{"line_number":574,"context_line":"            context \u003d args[0]"},{"line_number":575,"context_line":"            new_context, facade_tracker \u003d \\"},{"line_number":576,"context_line":"                self._get_facade_scope_tracker_w_copy(context)"},{"line_number":577,"context_line":"            with facade_tracker.transaction_scope() as trans_ctx:"}],"source_content_type":"text/x-python","patch_set":28,"id":"1a930d6b_0e2c2b4a","line":574,"in_reply_to":"3a961159_68d3b5d5","updated":"2015-01-20 20:20:24.000000000","message":"Victor - \n\nlike the other point, this is *all* in the spec.  those projects that don\u0027t use \"context\" in this way like keystone can alternatively use the contextmanager version, with a singleton / thread local for \"context\".\n\nI agree that not all projects use \"context\" like that and overall, switching to either style might require changes for any project, maybe some projects don\u0027t do it this way, but that was the whole point of the blueprint - I put all of this in there very specifically, I looked through many projects to see what they did (including Ironic, though granted, not all projects as there are tons), everyone read it, nobody -1\u0027ed it, it got approved.\n\nWhat\u0027s the point of writing a blueprint and getting everyone to approve it if we\u0027re just going to second-guess it all in the implementation ?","commit_id":"35859818c49d093d6cc81c145ab31e864733c6f4"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"2c86eba70f1064db0b80bb26faf500a65f2b02a2","unresolved":false,"context_lines":[{"line_number":512,"context_line":"        return transaction_contexts_by_thread"},{"line_number":513,"context_line":""},{"line_number":514,"context_line":"    def _transaction_context(self, context):"},{"line_number":515,"context_line":"        return self._transaction_contexts_by_thread(context).current"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    @contextlib.contextmanager"},{"line_number":518,"context_line":"    def _transaction_scope(self, context, new_transaction\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_b3475c76","line":515,"updated":"2015-01-26 12:21:11.000000000","message":"This raises an error if there\u0027s no context, which isn\u0027t what you want where it\u0027s used above. This wants to be:\n\n    return getattr(self._transaction_contexts_by_thread(context), \u0027current\u0027, None)\n\nI propose the following additional unit tests:\n\n    def test_session_no_context(self):\n        context \u003d oslo_context.RequestContext()\n        self.assertIsNone(context.session)\n\n    def test_connection_no_context(self):\n        context \u003d oslo_context.RequestContext()\n        self.assertIsNone(context.connection)\n\n    def test_transaction_no_context(self):\n        context \u003d oslo_context.RequestContext()\n        self.assertIsNone(context.transaction)","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"1913e3a97d4049a7f9682425583a8c8952452634","unresolved":false,"context_lines":[{"line_number":512,"context_line":"        return transaction_contexts_by_thread"},{"line_number":513,"context_line":""},{"line_number":514,"context_line":"    def _transaction_context(self, context):"},{"line_number":515,"context_line":"        return self._transaction_contexts_by_thread(context).current"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    @contextlib.contextmanager"},{"line_number":518,"context_line":"    def _transaction_scope(self, context, new_transaction\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_4019c020","line":515,"in_reply_to":"1a930d6b_2e8cb5d9","updated":"2015-01-27 15:26:56.000000000","message":"I really think it should be an exception.   Keeping it at least a subclass of AttributeError means that it is compatible with getattr(.., .., None), and if it\u0027s a subclass it can still be a special oslo.db exception with special catches available.\n\ncontext.session should never be referred to outside the proper scope.  as for model_query, that\u0027s an easy place for it to just call into special functions like enginefacade.get_session_or_none(context), something like that, though i think the session should be probably passed into model_query.  It\u0027s my strong desire for model_query to go away some day in favor of more query-integrated approaches.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"2faaaa54cb18d08ea09cc00b6d9190a820aeb34e","unresolved":false,"context_lines":[{"line_number":512,"context_line":"        return transaction_contexts_by_thread"},{"line_number":513,"context_line":""},{"line_number":514,"context_line":"    def _transaction_context(self, context):"},{"line_number":515,"context_line":"        return self._transaction_contexts_by_thread(context).current"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    @contextlib.contextmanager"},{"line_number":518,"context_line":"    def _transaction_scope(self, context, new_transaction\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_4048e0cb","line":515,"in_reply_to":"1a930d6b_4019c020","updated":"2015-01-27 15:34:45.000000000","message":"I\u0027m happy with any of the above solutions, as long as there is one.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"490741ed3716b4d3183810c0977d0ce896bda9f8","unresolved":false,"context_lines":[{"line_number":512,"context_line":"        return transaction_contexts_by_thread"},{"line_number":513,"context_line":""},{"line_number":514,"context_line":"    def _transaction_context(self, context):"},{"line_number":515,"context_line":"        return self._transaction_contexts_by_thread(context).current"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    @contextlib.contextmanager"},{"line_number":518,"context_line":"    def _transaction_scope(self, context, new_transaction\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_fd40bca6","line":515,"in_reply_to":"1a930d6b_b3475c76","updated":"2015-01-26 18:56:39.000000000","message":"I think \"context.session\" etc. should raise AttributeError when they are called outside of a decorator/contextmanager (however, this AttributeError should be raised as part of the descriptor, not as an accidental side effect of _transaction_context(), with a nice message and all that).  \n\nWhat is the use case for \"context.session\" to be called outside of a decorator/contextmanger, and why would someone expect calling upon an arbitrary attribute name from context *not* raise an AttributeError?  I see you mentioning something about the \"transition period\".  OK, so if there\u0027s code in the \"transitional\" nova that actually has to say, \"if context.session is None\", then why not put the getattr(.., .., None) there?  that pushes out the issue so that projects get enginefacade in its correct form.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"42c2a0f283d44bd34a98fd34cf152ede1d6799cf","unresolved":false,"context_lines":[{"line_number":512,"context_line":"        return transaction_contexts_by_thread"},{"line_number":513,"context_line":""},{"line_number":514,"context_line":"    def _transaction_context(self, context):"},{"line_number":515,"context_line":"        return self._transaction_contexts_by_thread(context).current"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    @contextlib.contextmanager"},{"line_number":518,"context_line":"    def _transaction_scope(self, context, new_transaction\u003dFalse):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_2e8cb5d9","line":515,"in_reply_to":"1a930d6b_fd40bca6","updated":"2015-01-27 09:46:05.000000000","message":"It\u0027s important that while we\u0027ve got a mixture of legacy and new facade we should be able to have a clean test for the availability of a session. In particular, everything calls model_query, so it needs to be able to determine where its session is coming from. Catching the current incidental error isn\u0027t a good solution. A well-defined exception would be fine, too. Whatever the solution, the unit tests will be a good measure of how tidy it is for the caller.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"2c86eba70f1064db0b80bb26faf500a65f2b02a2","unresolved":false,"context_lines":[{"line_number":520,"context_line":"            self._transaction_contexts_by_thread(context)"},{"line_number":521,"context_line":""},{"line_number":522,"context_line":"        current \u003d restore \u003d getattr("},{"line_number":523,"context_line":"            transaction_contexts_by_thread, \"current\", None)"},{"line_number":524,"context_line":""},{"line_number":525,"context_line":"        if new_transaction and current is not None:"},{"line_number":526,"context_line":"            current \u003d None"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_733894ef","line":523,"updated":"2015-01-26 12:21:11.000000000","message":"With the above change, this could be:\n\n    current \u003d restore \u003d self._transaction_context(context)","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"490741ed3716b4d3183810c0977d0ce896bda9f8","unresolved":false,"context_lines":[{"line_number":690,"context_line":"\"\"\"default context manager.\"\"\""},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"# apply the context manager to oslo.context.RequestContext"},{"line_number":693,"context_line":"_context_manager.transaction_context_provider(oslo_context.RequestContext)"},{"line_number":694,"context_line":""},{"line_number":695,"context_line":""},{"line_number":696,"context_line":"def configure(**kw):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_70287386","line":693,"updated":"2015-01-26 18:56:39.000000000","message":"can I get some guidance on what we want to do with this part? I didn\u0027t really understand what was proposed on the ML.   Looking at oslo_context, it is a super small library that also can be used by any number of projects that are not database related, so it seems much more appropriate that oslo.db has the depedency on oslo.context, not the other way around.   \n\nalso i dont understand the case of we dont want to patch-by-default at all, unless we\u0027re saying that we want an oslo_db.sqlalchemy dependency back in XYZ/context.py.    Or do we want this patch to occur as a product of calling _TransactionFactory._start() somehow ?    \n\nOverall, hoping we can stay out of the bikeshed on this one if we aren\u0027t in there already.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"2faaaa54cb18d08ea09cc00b6d9190a820aeb34e","unresolved":false,"context_lines":[{"line_number":690,"context_line":"\"\"\"default context manager.\"\"\""},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"# apply the context manager to oslo.context.RequestContext"},{"line_number":693,"context_line":"_context_manager.transaction_context_provider(oslo_context.RequestContext)"},{"line_number":694,"context_line":""},{"line_number":695,"context_line":""},{"line_number":696,"context_line":"def configure(**kw):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_e0eaac72","line":693,"in_reply_to":"1a930d6b_00989876","updated":"2015-01-27 15:34:45.000000000","message":"Currently decorating Nova\u0027s RequestContext object. Nova may want to move to oslo.context, but I don\u0027t want to gate this work on bikeshedding a separate design change.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"42c2a0f283d44bd34a98fd34cf152ede1d6799cf","unresolved":false,"context_lines":[{"line_number":690,"context_line":"\"\"\"default context manager.\"\"\""},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"# apply the context manager to oslo.context.RequestContext"},{"line_number":693,"context_line":"_context_manager.transaction_context_provider(oslo_context.RequestContext)"},{"line_number":694,"context_line":""},{"line_number":695,"context_line":""},{"line_number":696,"context_line":"def configure(**kw):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_79b84511","line":693,"in_reply_to":"1a930d6b_70287386","updated":"2015-01-27 09:46:05.000000000","message":"My request on the ML was that we should not force users to use oslo\u0027s RequestContext, as the dependency isn\u0027t strictly necessary. I want to be able to continue to apply _context_manager.transaction_context_provider() to any arbitrary class.\n\nI don\u0027t have an informed opinion on whether to patch oslo\u0027s RequestContext by default, or where to do that patching. I\u0027m personally happy with any solution which works for Nova, which this does by virtue of not using it. You won\u0027t get a -1 from me about this.","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"1913e3a97d4049a7f9682425583a8c8952452634","unresolved":false,"context_lines":[{"line_number":690,"context_line":"\"\"\"default context manager.\"\"\""},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"# apply the context manager to oslo.context.RequestContext"},{"line_number":693,"context_line":"_context_manager.transaction_context_provider(oslo_context.RequestContext)"},{"line_number":694,"context_line":""},{"line_number":695,"context_line":""},{"line_number":696,"context_line":"def configure(**kw):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1a930d6b_00989876","line":693,"in_reply_to":"1a930d6b_79b84511","updated":"2015-01-27 15:26:56.000000000","message":"OK that is fine, are you using the patcher in nova or the new RequestContext?  Why would nova *not* want to use oslo.context ?","commit_id":"bc33d20dc6db2f8e5f8cb02b4eb5f97d24dafb7a"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"20936514f0a60ec836065597b72b6c9973ec01b9","unresolved":false,"context_lines":[{"line_number":128,"context_line":"    def __init__(self):"},{"line_number":129,"context_line":"        self._url_cfg \u003d {"},{"line_number":130,"context_line":"            \u0027connection\u0027: _Default(),"},{"line_number":131,"context_line":"            \u0027slave_connection\u0027: _Default(),"},{"line_number":132,"context_line":"        }"},{"line_number":133,"context_line":"        self._engine_cfg \u003d {"},{"line_number":134,"context_line":"            \u0027sqlite_fk\u0027: _Default(False),"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_888578d0","line":131,"updated":"2015-02-06 15:51:57.000000000","message":"I think we need to redefine these connections. Apart from anything, we need 3 DB urls:\n\n1. Writer\n\n2. Sync reader\n\n3. Async reader\n\nIt\u0027s possible to have both sync and async slaves in a Galera cluster, for example, and we would be able to make use of both. Async in this case can mean \n\nOf these 3 only writer is required, so for convenience we could leave that called \u0027connection\u0027. We should deprecate the existing \u0027slave_connection\u0027 opt in favour of the clearer \u0027async_read_connection\u0027. Their meanings are equivalent. We should also create \u0027sync_read_connection\u0027, which doesn\u0027t currently have an equivalent.\n\nIt is then down to the site administrator to define these connection URLs according to their needs.","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"fad73464978fa2e459b413387694913fc194846f","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            \u0027connection\u0027: _Default(),"},{"line_number":131,"context_line":"            \u0027slave_connection\u0027: _Default(),"},{"line_number":132,"context_line":"        }"},{"line_number":133,"context_line":"        self._engine_cfg \u003d {"},{"line_number":134,"context_line":"            \u0027sqlite_fk\u0027: _Default(False),"},{"line_number":135,"context_line":"            \u0027mysql_sql_mode\u0027: _Default(\u0027TRADITIONAL\u0027),"},{"line_number":136,"context_line":"            \u0027idle_timeout\u0027: _Default(3600),"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_bb1bd1c8","line":133,"updated":"2015-02-04 17:04:12.000000000","message":"This is replicating the defaults which are already defined in, and returned by, database_opts. I don\u0027t think we should be replicating these defaults. I\u0027ve admittedly only read the description of where defaults come from in this code once, but I\u0027m now confused :) What if I modify a default here, but not in database_opts. How about vice versa?\n\nWhy do we need a different way to specify defaults? If we do, shouldn\u0027t that live in oslo_config?","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"20936514f0a60ec836065597b72b6c9973ec01b9","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            \u0027connection\u0027: _Default(),"},{"line_number":131,"context_line":"            \u0027slave_connection\u0027: _Default(),"},{"line_number":132,"context_line":"        }"},{"line_number":133,"context_line":"        self._engine_cfg \u003d {"},{"line_number":134,"context_line":"            \u0027sqlite_fk\u0027: _Default(False),"},{"line_number":135,"context_line":"            \u0027mysql_sql_mode\u0027: _Default(\u0027TRADITIONAL\u0027),"},{"line_number":136,"context_line":"            \u0027idle_timeout\u0027: _Default(3600),"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_e84c34ca","line":133,"in_reply_to":"da86d52c_0aef13ea","updated":"2015-02-06 15:51:57.000000000","message":"Ok, yes, I see they were there before. I was just surprised by the new default code.\n\nThis is still an area in need of cleanup, but I agree it\u0027s not important right now.","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"431e7ace1f34531fced883d765bf57f29b68fa1e","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            \u0027connection\u0027: _Default(),"},{"line_number":131,"context_line":"            \u0027slave_connection\u0027: _Default(),"},{"line_number":132,"context_line":"        }"},{"line_number":133,"context_line":"        self._engine_cfg \u003d {"},{"line_number":134,"context_line":"            \u0027sqlite_fk\u0027: _Default(False),"},{"line_number":135,"context_line":"            \u0027mysql_sql_mode\u0027: _Default(\u0027TRADITIONAL\u0027),"},{"line_number":136,"context_line":"            \u0027idle_timeout\u0027: _Default(3600),"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_0aef13ea","line":133,"in_reply_to":"da86d52c_bb1bd1c8","updated":"2015-02-04 17:57:25.000000000","message":"this is for total backwards compatibility with EngineFacade.   I\u0027m all for changing around configuration between oslo_config and oslo_db but that is not in scope for this.   I think we should merge this now and then look to changes in the EngineFacade/config contract second.     I had to make this a little more comprehensive than it was because I need to specify configs that supersede those of cfg.CONF.","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"20936514f0a60ec836065597b72b6c9973ec01b9","unresolved":false,"context_lines":[{"line_number":149,"context_line":"            \u0027__autocommit\u0027: True"},{"line_number":150,"context_line":"        }"},{"line_number":151,"context_line":"        self._transaction_ctx_cfg \u003d {"},{"line_number":152,"context_line":"            \u0027rollback_reader_sessions\u0027: False,"},{"line_number":153,"context_line":"            }"},{"line_number":154,"context_line":"        self._facade_cfg \u003d {"},{"line_number":155,"context_line":"            \u0027synchronous_reader\u0027: True"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_4805400f","line":152,"updated":"2015-02-06 15:51:57.000000000","message":"Aside: do we need this? I can\u0027t imagine when we\u0027d ever want to use it. Might be better to remove it.","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"20936514f0a60ec836065597b72b6c9973ec01b9","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            \u0027rollback_reader_sessions\u0027: False,"},{"line_number":153,"context_line":"            }"},{"line_number":154,"context_line":"        self._facade_cfg \u003d {"},{"line_number":155,"context_line":"            \u0027synchronous_reader\u0027: True"},{"line_number":156,"context_line":"        }"},{"line_number":157,"context_line":""},{"line_number":158,"context_line":"        # other options that are defined in oslo.db.options.database_opts"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_68e764ac","line":155,"updated":"2015-02-06 15:51:57.000000000","message":"See above. We can have both synchronous and asynchronous readers, and make use of both.\n\nhttp://www.severalnines.com/blog/asynchronous-replication-galera-cluster-mysql-server-gtid","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"fad73464978fa2e459b413387694913fc194846f","unresolved":false,"context_lines":[{"line_number":207,"context_line":"        Behavior here is the same as that of"},{"line_number":208,"context_line":"        :meth:`._TransactionFactory.configure_defaults`,"},{"line_number":209,"context_line":"        with the exception that values specified here will **supersede** those"},{"line_number":210,"context_line":"        setup in the :class:`.oslo.config.cfg.ConfigOpts` options."},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"        .. seealso::"},{"line_number":213,"context_line":""}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_5b8bb5c2","line":210,"updated":"2015-02-04 17:04:12.000000000","message":"Why are we doing this?","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"431e7ace1f34531fced883d765bf57f29b68fa1e","unresolved":false,"context_lines":[{"line_number":207,"context_line":"        Behavior here is the same as that of"},{"line_number":208,"context_line":"        :meth:`._TransactionFactory.configure_defaults`,"},{"line_number":209,"context_line":"        with the exception that values specified here will **supersede** those"},{"line_number":210,"context_line":"        setup in the :class:`.oslo.config.cfg.ConfigOpts` options."},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"        .. seealso::"},{"line_number":213,"context_line":""}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_eac8ff56","line":210,"in_reply_to":"da86d52c_5b8bb5c2","updated":"2015-02-04 17:57:25.000000000","message":"because I need it in the tests and also it seems likely that one would expect that calling enginefacade.config(x \u003d \u0027y\u0027) would supersede a value that\u0027s in cfg.CONF.    There\u0027s not a fully defined system of which keys are in cfg.CONF and which aren\u0027t, which are defaults here and which arent;  this API makes it clear what will happen when.   as for the rationale behind configure() itself, it\u0027s in the blueprint, to accommodate the in-module configuration we see for EngineFacade use today.\n\nnothing has really changed here vs. the previous 30 patches, just there\u0027s now \"default_configure()\" and \"configure()\"  It\u0027s one extra public API method.   That\u0027s all we should be looking at right now as far as this part of it.","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"20936514f0a60ec836065597b72b6c9973ec01b9","unresolved":false,"context_lines":[{"line_number":258,"context_line":""},{"line_number":259,"context_line":"        return self._legacy_facade"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"    def _create_connection(self, writer):"},{"line_number":262,"context_line":"        if not self._started:"},{"line_number":263,"context_line":"            self._start()"},{"line_number":264,"context_line":"        if writer is _WRITER:"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_df93b1a0","line":261,"updated":"2015-02-06 15:51:57.000000000","message":"Readability point: \u0027writer\u0027 doesn\u0027t really make sense here any more. Something like \u0027mode\u0027 would be more appropriate.\n\n...and throughout...","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"20936514f0a60ec836065597b72b6c9973ec01b9","unresolved":false,"context_lines":[{"line_number":396,"context_line":"    \"\"\"Represent a single database transaction in progress.\"\"\""},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"    def __init__("},{"line_number":399,"context_line":"            self, factory, rollback_reader_sessions\u003dFalse):"},{"line_number":400,"context_line":"        \"\"\"Construct a new :class:`.TransactionContext`."},{"line_number":401,"context_line":""},{"line_number":402,"context_line":"        :param factory: the :class:`.TransactionFactory` which will"}],"source_content_type":"text/x-python","patch_set":37,"id":"da86d52c_3f612da9","line":399,"updated":"2015-02-06 15:51:57.000000000","message":"nit: Was this line break intentional?","commit_id":"db3b7ab45d60a75f28823e4f4585fecb703f1810"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8d61749fd3491b361c86462442213e644260c6a5","unresolved":false,"context_lines":[{"line_number":26,"context_line":"from oslo_db.sqlalchemy import orm"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"class _symbol(object):"},{"line_number":30,"context_line":"    \"\"\"represent a fixed symbol.\"\"\""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    __slots__ \u003d \u0027name\u0027,"}],"source_content_type":"text/x-python","patch_set":41,"id":"9a80dd14_057e2019","line":29,"updated":"2015-03-08 00:07:44.000000000","message":"Wouldn\u0027t a const string work just as well? :)","commit_id":"5a3fa04b1df130d23fbfe8d4c66e969f64914ceb"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"27495454567ea4eb2740123e91a515339d99d8c0","unresolved":false,"context_lines":[{"line_number":26,"context_line":"from oslo_db.sqlalchemy import orm"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"class _symbol(object):"},{"line_number":30,"context_line":"    \"\"\"represent a fixed symbol.\"\"\""},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    __slots__ \u003d \u0027name\u0027,"}],"source_content_type":"text/x-python","patch_set":41,"id":"7ad32947_bd5ea074","line":29,"in_reply_to":"9a80dd14_057e2019","updated":"2015-04-27 16:22:28.000000000","message":"a symbol object can be safely compared using \"is\".  i guess by \"const string\" you mean everyone refers to the same string reference so they can use \"is\".  shrugs, I like that comparing to \"symbol \u003d\u003d \u0027IMASTRING\u0027\" is not even an option :).","commit_id":"5a3fa04b1df130d23fbfe8d4c66e969f64914ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8d61749fd3491b361c86462442213e644260c6a5","unresolved":false,"context_lines":[{"line_number":39,"context_line":""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"_ASYNC_READER \u003d _symbol(\u0027ASYNC_READER\u0027)"},{"line_number":42,"context_line":"\"\"\"Represent the transaction state of \"async reader\"."},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"This state indicates that the transaction is a read-only and is"},{"line_number":45,"context_line":"safe to use on an asynchronously updated slave database."}],"source_content_type":"text/x-python","patch_set":41,"id":"9a80dd14_257b2429","line":42,"updated":"2015-03-08 00:07:44.000000000","message":"Here and for _READER and _WRITER, does this really represent the *state* of a transaction, or does it represent the *type* of data access that a session has requested?","commit_id":"5a3fa04b1df130d23fbfe8d4c66e969f64914ceb"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"27495454567ea4eb2740123e91a515339d99d8c0","unresolved":false,"context_lines":[{"line_number":39,"context_line":""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"_ASYNC_READER \u003d _symbol(\u0027ASYNC_READER\u0027)"},{"line_number":42,"context_line":"\"\"\"Represent the transaction state of \"async reader\"."},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"This state indicates that the transaction is a read-only and is"},{"line_number":45,"context_line":"safe to use on an asynchronously updated slave database."}],"source_content_type":"text/x-python","patch_set":41,"id":"7ad32947_bd16a053","line":42,"in_reply_to":"9a80dd14_257b2429","updated":"2015-04-27 16:22:28.000000000","message":"from this perspective it really only represents which of the \"engine\" configurations we are using for the current operation.  If there are two engine URLs and one is \"writer\" the other is \"reader\", that is.  it also impacts what we do at the end of the transaction, a reader we might not be calling commit.","commit_id":"5a3fa04b1df130d23fbfe8d4c66e969f64914ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8d61749fd3491b361c86462442213e644260c6a5","unresolved":false,"context_lines":[{"line_number":41,"context_line":"_ASYNC_READER \u003d _symbol(\u0027ASYNC_READER\u0027)"},{"line_number":42,"context_line":"\"\"\"Represent the transaction state of \"async reader\"."},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"This state indicates that the transaction is a read-only and is"},{"line_number":45,"context_line":"safe to use on an asynchronously updated slave database."},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"\"\"\""}],"source_content_type":"text/x-python","patch_set":41,"id":"9a80dd14_25940442","line":44,"updated":"2015-03-08 00:07:44.000000000","message":"s/is a/is/","commit_id":"5a3fa04b1df130d23fbfe8d4c66e969f64914ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8d61749fd3491b361c86462442213e644260c6a5","unresolved":false,"context_lines":[{"line_number":49,"context_line":"_READER \u003d _symbol(\u0027READER\u0027)"},{"line_number":50,"context_line":"\"\"\"Represent the transaction state of \"reader\"."},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"This state indicates that the transaction is a read-only and is"},{"line_number":53,"context_line":"only safe to use on a synchronously updated slave database; otherwise"},{"line_number":54,"context_line":"the master database should be used."},{"line_number":55,"context_line":""}],"source_content_type":"text/x-python","patch_set":41,"id":"9a80dd14_459d7865","line":52,"updated":"2015-03-08 00:07:44.000000000","message":"s/is a/is/","commit_id":"5a3fa04b1df130d23fbfe8d4c66e969f64914ceb"},{"author":{"_account_id":1297,"name":"Joshua Harlow","email":"jxharlow@godaddy.com","username":"harlowja"},"change_message_id":"5058d2abf8e92f19008445991ae07c048ab2278f","unresolved":false,"context_lines":[{"line_number":482,"context_line":"                self._end_session_transaction(self.session)"},{"line_number":483,"context_line":"            except Exception:"},{"line_number":484,"context_line":"                self.session.rollback()"},{"line_number":485,"context_line":"                # TODO(zzzeek) do we need save_and_reraise() here,"},{"line_number":486,"context_line":"                # or do newer eventlets not have issues?  we are using"},{"line_number":487,"context_line":"                # raw \"raise\" in many other places in oslo.db already"},{"line_number":488,"context_line":"                # (and one six.reraise())."}],"source_content_type":"text/x-python","patch_set":42,"id":"7a016987_18c58b3b","line":485,"updated":"2015-05-15 00:16:36.000000000","message":"I\u0027m 95% confident we don\u0027t need `save_and_reraise` anymore.","commit_id":"00ab35b3962812acbe5c9e84f1bd850fd0184615"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"b8f35cdde466c6baf78fd3332f3c3b748d8d3438","unresolved":false,"context_lines":[{"line_number":669,"context_line":""},{"line_number":670,"context_line":"    @contextlib.contextmanager"},{"line_number":671,"context_line":"    def _transaction_scope(self, context):"},{"line_number":672,"context_line":"        if self._replace:"},{"line_number":673,"context_line":"            restore_factory \u003d _context_manager._root._root_factory"},{"line_number":674,"context_line":"            _context_manager._root._root_factory \u003d self._root._root_factory"},{"line_number":675,"context_line":""}],"source_content_type":"text/x-python","patch_set":43,"id":"5afe65bd_837bed8b","line":672,"updated":"2015-06-04 13:49:46.000000000","message":"question: should \"replace\" here be threading local?  it seems like if we are doing \"with mgr.replace.using(context):\", we\u0027d only expect that to be in the current thread.  If we are trying to replace the transaction factory *globally* across the whole app, that would be a directive outside of context managers / decorators.","commit_id":"5e0d0b98f771ec711e9b5e6a738c5edd8b2e39a5"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"232aefb2e5b3903ff8d0d296ba25143b41f05275","unresolved":false,"context_lines":[{"line_number":278,"context_line":"            kw[\u0027bind\u0027] \u003d bind"},{"line_number":279,"context_line":"        if mode is _WRITER:"},{"line_number":280,"context_line":"            return self._writer_maker(**kw)"},{"line_number":281,"context_line":"        elif self.synchronous_reader or mode is _ASYNC_READER:"},{"line_number":282,"context_line":"            return self._reader_maker(**kw)"},{"line_number":283,"context_line":"        else:"},{"line_number":284,"context_line":"            return self._writer_maker(**kw)"}],"source_content_type":"text/x-python","patch_set":44,"id":"3afb71cf_5674c066","line":281,"updated":"2015-06-08 16:02:48.000000000","message":"hmm, I must be missing something. but shouldn\u0027t this be \"not self.synchronous_reader\"? as _reader_maker() seems to produce connection to an asynchronous slave","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"c058c702007ec3585b405a10d1512fcdd27a38f7","unresolved":false,"context_lines":[{"line_number":278,"context_line":"            kw[\u0027bind\u0027] \u003d bind"},{"line_number":279,"context_line":"        if mode is _WRITER:"},{"line_number":280,"context_line":"            return self._writer_maker(**kw)"},{"line_number":281,"context_line":"        elif self.synchronous_reader or mode is _ASYNC_READER:"},{"line_number":282,"context_line":"            return self._reader_maker(**kw)"},{"line_number":283,"context_line":"        else:"},{"line_number":284,"context_line":"            return self._writer_maker(**kw)"}],"source_content_type":"text/x-python","patch_set":44,"id":"3afb71cf_ab4ee693","line":281,"in_reply_to":"3afb71cf_5674c066","updated":"2015-06-08 19:37:51.000000000","message":"so if we\u0027re using galera, this is an option that says, \"any galera node is good as a reader, even if we want it to be \u0027synchronous\u0027 with the writer\".  It depends on the application\u0027s perspective on the extremely tiny lag that occurs on Galera between nodes; if the app doesn\u0027t mix up sibling reader/writer calls in one API call, then there\u0027s no reason it has to use the \"async_reader\" marker everywhere.  \n\nBasically an application might not want to bother with \"reader\" and \"async_reader\" separately.  Originally there was no \"async_reader\" setting.","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"0c153bf4aa0baedc162ccab4395e229863aa3e10","unresolved":false,"context_lines":[{"line_number":278,"context_line":"            kw[\u0027bind\u0027] \u003d bind"},{"line_number":279,"context_line":"        if mode is _WRITER:"},{"line_number":280,"context_line":"            return self._writer_maker(**kw)"},{"line_number":281,"context_line":"        elif self.synchronous_reader or mode is _ASYNC_READER:"},{"line_number":282,"context_line":"            return self._reader_maker(**kw)"},{"line_number":283,"context_line":"        else:"},{"line_number":284,"context_line":"            return self._writer_maker(**kw)"}],"source_content_type":"text/x-python","patch_set":44,"id":"fa32b979_b96805bc","line":281,"in_reply_to":"3afb71cf_ab4ee693","updated":"2015-06-14 06:15:34.000000000","message":"Got it. Makes sense.","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"}],"oslo_db/sqlalchemy/orm.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a0adc18bf37a321081a2a7ca2c637bb21641a5ba","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"class Query(sqlalchemy.orm.query.Query):"},{"line_number":25,"context_line":"    \"\"\"Subclass of sqlalchemy.query with soft_delete() method.\"\"\""},{"line_number":26,"context_line":"    def soft_delete(self, synchronize_session\u003d\u0027evaluate\u0027):"},{"line_number":27,"context_line":"        return self.update({\u0027deleted\u0027: literal_column(\u0027id\u0027),"},{"line_number":28,"context_line":"                            \u0027updated_at\u0027: literal_column(\u0027updated_at\u0027),"},{"line_number":29,"context_line":"                            \u0027deleted_at\u0027: timeutils.utcnow()},"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_3bda404b","line":26,"updated":"2015-01-16 02:39:48.000000000","message":"die. :)","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"74b19e67d2dae2574e0c87af3f5d3c588f00b43e","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"class Query(sqlalchemy.orm.query.Query):"},{"line_number":25,"context_line":"    \"\"\"Subclass of sqlalchemy.query with soft_delete() method.\"\"\""},{"line_number":26,"context_line":"    def soft_delete(self, synchronize_session\u003d\u0027evaluate\u0027):"},{"line_number":27,"context_line":"        return self.update({\u0027deleted\u0027: literal_column(\u0027id\u0027),"},{"line_number":28,"context_line":"                            \u0027updated_at\u0027: literal_column(\u0027updated_at\u0027),"},{"line_number":29,"context_line":"                            \u0027deleted_at\u0027: timeutils.utcnow()},"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_861114fa","line":26,"in_reply_to":"3a961159_3bda404b","updated":"2015-01-16 13:40:19.000000000","message":"I detect some feeling there :) Is soft_delete() problematic?","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"8152716654d249f570d349ab47f2ac200b307fa8","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"class Query(sqlalchemy.orm.query.Query):"},{"line_number":25,"context_line":"    \"\"\"Subclass of sqlalchemy.query with soft_delete() method.\"\"\""},{"line_number":26,"context_line":"    def soft_delete(self, synchronize_session\u003d\u0027evaluate\u0027):"},{"line_number":27,"context_line":"        return self.update({\u0027deleted\u0027: literal_column(\u0027id\u0027),"},{"line_number":28,"context_line":"                            \u0027updated_at\u0027: literal_column(\u0027updated_at\u0027),"},{"line_number":29,"context_line":"                            \u0027deleted_at\u0027: timeutils.utcnow()},"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_deb5917d","line":26,"in_reply_to":"3a961159_861114fa","updated":"2015-01-16 18:58:22.000000000","message":"soft deletes are a huge problem.  but not the one we\u0027ve come here to solve :).","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"}],"oslo_db/sqlalchemy/session.py":[{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        except exception.DBDuplicateEntry as e:"},{"line_number":113,"context_line":"            handle_error(e)"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"* The enginefacade system eliminates the need to decide when sessions need"},{"line_number":116,"context_line":"  to be passed between methods.   All methods should instead share a common"},{"line_number":117,"context_line":"  context object; the enginefacade system will maintain the transaction"},{"line_number":118,"context_line":"  across method calls."}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_c94cd6cc","line":115,"updated":"2015-01-19 16:01:06.000000000","message":"\\o/","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":168,"context_line":""},{"line_number":169,"context_line":"        @enginefacade.writer"},{"line_number":170,"context_line":"        def complex_soft_delete_with_synchronization_bar(context):"},{"line_number":171,"context_line":"            # use synchronize_session\u003d\u0027evaulate\u0027 when you\u0027d like to attempt"},{"line_number":172,"context_line":"            # to update the state of the Session to match that of the DELETE."},{"line_number":173,"context_line":"            # This is potentially helpful if the operation is complex and"},{"line_number":174,"context_line":"            # continues to work with instances that were loaded, though"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_69e4c2a8","line":171,"updated":"2015-01-19 16:01:06.000000000","message":"nit typo: evaluate","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":168,"context_line":""},{"line_number":169,"context_line":"        @enginefacade.writer"},{"line_number":170,"context_line":"        def complex_soft_delete_with_synchronization_bar(context):"},{"line_number":171,"context_line":"            # use synchronize_session\u003d\u0027evaulate\u0027 when you\u0027d like to attempt"},{"line_number":172,"context_line":"            # to update the state of the Session to match that of the DELETE."},{"line_number":173,"context_line":"            # This is potentially helpful if the operation is complex and"},{"line_number":174,"context_line":"            # continues to work with instances that were loaded, though"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_41b7d621","line":171,"in_reply_to":"3a961159_69e4c2a8","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"952a49e17035a8bd96e49e287f7712241cb84cd5","unresolved":false,"context_lines":[{"line_number":189,"context_line":"EngineFacade \u003d enginefacade.LegacyEngineFacade"},{"line_number":190,"context_line":"create_engine \u003d engines.create_engine"},{"line_number":191,"context_line":"get_maker \u003d orm.get_maker"},{"line_number":192,"context_line":"__all__ \u003d [\"EngineFacade\", \"create_engine\", \"get_maker\"]"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_69404260","line":192,"updated":"2015-01-19 16:01:06.000000000","message":"we should probably expose Session and Query classes here for backwards compatibility (though, I doubt anyone is using them directly, but still...)","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":189,"context_line":"EngineFacade \u003d enginefacade.LegacyEngineFacade"},{"line_number":190,"context_line":"create_engine \u003d engines.create_engine"},{"line_number":191,"context_line":"get_maker \u003d orm.get_maker"},{"line_number":192,"context_line":"__all__ \u003d [\"EngineFacade\", \"create_engine\", \"get_maker\"]"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_c15906ff","line":192,"in_reply_to":"3a961159_69404260","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"232aefb2e5b3903ff8d0d296ba25143b41f05275","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        foo_ref.save(context.session)"},{"line_number":45,"context_line":"        return foo_ref"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"  In the above system, transactions are committed automatically, and"},{"line_number":48,"context_line":"  are shared among all dependent database methods.   Ensure"},{"line_number":49,"context_line":"  that methods which \"write\" data are enclosed within @writer blocks."},{"line_number":50,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"3afb71cf_eabf465e","line":47,"updated":"2015-06-08 16:02:48.000000000","message":"just wondering, what if we need an explicit commit (e.g. to make the results visible for concurrent transactions)? AFAIU, context.session.commit() won\u0027t issue a COMMIT as session is created on the base of an existing connection","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"0c153bf4aa0baedc162ccab4395e229863aa3e10","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        foo_ref.save(context.session)"},{"line_number":45,"context_line":"        return foo_ref"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"  In the above system, transactions are committed automatically, and"},{"line_number":48,"context_line":"  are shared among all dependent database methods.   Ensure"},{"line_number":49,"context_line":"  that methods which \"write\" data are enclosed within @writer blocks."},{"line_number":50,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"fa32b979_79627dda","line":47,"in_reply_to":"3afb71cf_a6517b10","updated":"2015-06-14 06:15:34.000000000","message":"Agreed. Thanks for the clarifications!","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"c058c702007ec3585b405a10d1512fcdd27a38f7","unresolved":false,"context_lines":[{"line_number":44,"context_line":"        foo_ref.save(context.session)"},{"line_number":45,"context_line":"        return foo_ref"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"  In the above system, transactions are committed automatically, and"},{"line_number":48,"context_line":"  are shared among all dependent database methods.   Ensure"},{"line_number":49,"context_line":"  that methods which \"write\" data are enclosed within @writer blocks."},{"line_number":50,"context_line":""}],"source_content_type":"text/x-python","patch_set":44,"id":"3afb71cf_a6517b10","line":47,"in_reply_to":"3afb71cf_eabf465e","updated":"2015-06-08 19:37:51.000000000","message":"right now the plan for a method that wants its results to be committed independently of the context is to use enginefacade.writer.independent, which will have it use a brand new transaction.\n\nas far as emitting a \"commit\" in the middle of a nested context, I\u0027d be concerned that the methods which call this one might not be ready for that to happen; e.g. if the enclosing call does some things, then might do a rollback for some reason, now its data won\u0027t get rolled back if it happens to call some nested function that does this standalone COMMIT.\n\nso i think keeping that only available at the \"nested\" level might keep this safer as far as heavily nested code not having hard-to-predict side effects.","commit_id":"fdbd928b1fdf0334e1740e565ab8206fff54eaa6"}],"oslo_db/tests/sqlalchemy/test_enginefacade.py":[{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"74b19e67d2dae2574e0c87af3f5d3c588f00b43e","unresolved":false,"context_lines":[{"line_number":92,"context_line":"        engine_patch \u003d mock.patch.object("},{"line_number":93,"context_line":"            engines, \"create_engine\", mock.Mock(return_value\u003dself.engine))"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"        self.get_maker \u003d session_patch.start()"},{"line_number":96,"context_line":"        self.create_engine \u003d engine_patch.start()"},{"line_number":97,"context_line":"        self.factory \u003d enginefacade._TransactionFactory()"},{"line_number":98,"context_line":"        facade_patcher \u003d mock.patch.object("}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_2c6841b9","line":95,"updated":"2015-01-16 13:40:19.000000000","message":"Suggestion: I\u0027m paranoid about leaky mocks. When I\u0027ve used the start/stop pattern like this before I\u0027ve put the cleanup immediately following mock.start().\n\nI realise this is setUp, and we really shouldn\u0027t have any failures here! This code is fine. I\u0027m still paranoid, though.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"8152716654d249f570d349ab47f2ac200b307fa8","unresolved":false,"context_lines":[{"line_number":92,"context_line":"        engine_patch \u003d mock.patch.object("},{"line_number":93,"context_line":"            engines, \"create_engine\", mock.Mock(return_value\u003dself.engine))"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"        self.get_maker \u003d session_patch.start()"},{"line_number":96,"context_line":"        self.create_engine \u003d engine_patch.start()"},{"line_number":97,"context_line":"        self.factory \u003d enginefacade._TransactionFactory()"},{"line_number":98,"context_line":"        facade_patcher \u003d mock.patch.object("}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_9ea4e9b9","line":95,"in_reply_to":"3a961159_2c6841b9","updated":"2015-01-16 18:58:22.000000000","message":"If we\u0027re being paranoid about code that has no reason to break just breaking, wouldn\u0027t it be even safer to put the addCleanup *before* we even call start()? \n\nMore practically, the _TransactionFactory() being invoked would have more of a chance of \"failure\" since that\u0027s the thing we\u0027re testing so I can move up the cleanups for that reason.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":92,"context_line":"        engine_patch \u003d mock.patch.object("},{"line_number":93,"context_line":"            engines, \"create_engine\", mock.Mock(return_value\u003dself.engine))"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"        self.get_maker \u003d session_patch.start()"},{"line_number":96,"context_line":"        self.create_engine \u003d engine_patch.start()"},{"line_number":97,"context_line":"        self.factory \u003d enginefacade._TransactionFactory()"},{"line_number":98,"context_line":"        facade_patcher \u003d mock.patch.object("}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_81061ecc","line":95,"in_reply_to":"3a961159_9ea4e9b9","updated":"2015-01-19 18:38:30.000000000","message":"Done - each cleanup is moved directly underneath the corresponding \"start\"","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":223,"context_line":"        self.assertEqual(session.mock_calls, self.session.mock_calls)"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"class MockFacadeTest(MockFacadeTestBase):"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    def test_session_reader_decorator(self):"},{"line_number":229,"context_line":"        context \u003d MockContext()"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_b1d72fed","line":226,"updated":"2015-01-16 04:31:18.000000000","message":"we can probably re-merge MockFacadeTestBase here as the base isn\u0027t re-used","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":223,"context_line":"        self.assertEqual(session.mock_calls, self.session.mock_calls)"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"class MockFacadeTest(MockFacadeTestBase):"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    def test_session_reader_decorator(self):"},{"line_number":229,"context_line":"        context \u003d MockContext()"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_01194e23","line":226,"in_reply_to":"3a961159_b1d72fed","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":9555,"name":"Matthew Booth","email":"mbooth@redhat.com","username":"MatthewBooth"},"change_message_id":"74b19e67d2dae2574e0c87af3f5d3c588f00b43e","unresolved":false,"context_lines":[{"line_number":364,"context_line":""},{"line_number":365,"context_line":"        with self._assert_engine() as engine:"},{"line_number":366,"context_line":"            with self._assert_maker(engine) as maker:"},{"line_number":367,"context_line":"                go1(context)"},{"line_number":368,"context_line":"                with self._assert_reader_session(maker) as session:"},{"line_number":369,"context_line":"                    session.execute(\"test1\")"},{"line_number":370,"context_line":"                go2(context)"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_4cd66dc4","line":367,"updated":"2015-01-16 13:40:19.000000000","message":"It would be more consistent if the go1() and go2() calls were above, immediately below their definitions. The other tests read like:\n\nDo THIS\nAssert equivalent to:\n  Do THAT","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"8152716654d249f570d349ab47f2ac200b307fa8","unresolved":false,"context_lines":[{"line_number":364,"context_line":""},{"line_number":365,"context_line":"        with self._assert_engine() as engine:"},{"line_number":366,"context_line":"            with self._assert_maker(engine) as maker:"},{"line_number":367,"context_line":"                go1(context)"},{"line_number":368,"context_line":"                with self._assert_reader_session(maker) as session:"},{"line_number":369,"context_line":"                    session.execute(\"test1\")"},{"line_number":370,"context_line":"                go2(context)"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_feda4de7","line":367,"in_reply_to":"3a961159_4cd66dc4","updated":"2015-01-16 18:58:22.000000000","message":"absolutely.  As this code is however, the _assert_reader_session() call asserts that the session was used within the scope of which it produced it\u0027s comparison session, which in this instance has only done half of its work so far.  that is, if you move go1()/go2() up, you get this failure:\n\n\tMismatchError: !\u003d:\n\treference \u003d [call.begin(), call.execute(\u0027test1\u0027), call.close()]\n\tactual    \u003d [call.begin(),\n\t call.execute(\u0027test1\u0027),\n\t call.close(),\n\t call.begin(),\n\t call.execute(\u0027test2\u0027),\n\t call.commit(),\n\t call.close()]\n\nWhen I hit this issue, I had the option of either opening up _assert_XYZ_session() to do things differently somehow, which I feared would make the whole thing even more complicated than it already is, or just putting these inline.   \n\nThe good news is that because you asked me about this, I had to wrap my head around it again to re-understand how it works, and I can just add an extra flag to _assert_XYZ_session telling it to only assert the session calls the second time.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":364,"context_line":""},{"line_number":365,"context_line":"        with self._assert_engine() as engine:"},{"line_number":366,"context_line":"            with self._assert_maker(engine) as maker:"},{"line_number":367,"context_line":"                go1(context)"},{"line_number":368,"context_line":"                with self._assert_reader_session(maker) as session:"},{"line_number":369,"context_line":"                    session.execute(\"test1\")"},{"line_number":370,"context_line":"                go2(context)"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_81d45e20","line":367,"in_reply_to":"3a961159_feda4de7","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":495,"context_line":"            session"},{"line_number":496,"context_line":"        )"},{"line_number":497,"context_line":""},{"line_number":498,"context_line":"    def test_thread_ctxmanager_writer(self):"},{"line_number":499,"context_line":"        context \u003d MockContext()"},{"line_number":500,"context_line":""},{"line_number":501,"context_line":"        ident \u003d 1"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_31adff84","line":498,"updated":"2015-01-16 04:31:18.000000000","message":"these thread tests should be on a different fixture that only is on sqlite and doesn\u0027t create a table, since we are just testing connection and session identity.","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":495,"context_line":"            session"},{"line_number":496,"context_line":"        )"},{"line_number":497,"context_line":""},{"line_number":498,"context_line":"    def test_thread_ctxmanager_writer(self):"},{"line_number":499,"context_line":"        context \u003d MockContext()"},{"line_number":500,"context_line":""},{"line_number":501,"context_line":"        ident \u003d 1"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_e177e23a","line":498,"in_reply_to":"3a961159_31adff84","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":802,"context_line":""},{"line_number":803,"context_line":"    @test_base.backend_specific(\"postgresql\", \"mysql\")"},{"line_number":804,"context_line":"    def test_linked_external_connection_transaction(self):"},{"line_number":805,"context_line":"        \"\"\"Test the ``_link()`` and ``.transaction`` features together.\"\"\""},{"line_number":806,"context_line":""},{"line_number":807,"context_line":"        context \u003d MockContext()"},{"line_number":808,"context_line":"        with enginefacade.using_writer_connection(context) as conn1:"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_d1d2fbfb","line":805,"updated":"2015-01-16 04:31:18.000000000","message":"this isn\u0027t called _link() anymore, we\u0027re just testing deepcopy w/ transaction().","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":802,"context_line":""},{"line_number":803,"context_line":"    @test_base.backend_specific(\"postgresql\", \"mysql\")"},{"line_number":804,"context_line":"    def test_linked_external_connection_transaction(self):"},{"line_number":805,"context_line":"        \"\"\"Test the ``_link()`` and ``.transaction`` features together.\"\"\""},{"line_number":806,"context_line":""},{"line_number":807,"context_line":"        context \u003d MockContext()"},{"line_number":808,"context_line":"        with enginefacade.using_writer_connection(context) as conn1:"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_a195da33","line":805,"in_reply_to":"3a961159_d1d2fbfb","updated":"2015-01-19 18:38:30.000000000","message":"Done, as well as \"linked\" on line 435","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"5b27d01d6bdb41173290a7d4c535bff5fcdda35c","unresolved":false,"context_lines":[{"line_number":885,"context_line":"            [(\"u1_commit\",)]"},{"line_number":886,"context_line":"        )"},{"line_number":887,"context_line":""},{"line_number":888,"context_line":"    def test_legacy_integration(self):"},{"line_number":889,"context_line":"        legacy_facade \u003d enginefacade.get_legacy_facade()"},{"line_number":890,"context_line":"        self.assertTrue("},{"line_number":891,"context_line":"            legacy_facade.get_engine() is"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_31e41fdf","line":888,"updated":"2015-01-16 04:31:18.000000000","message":"also should be in the \"not a mock, but is only SQLite w/ no tables\" fixture","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"2c26ced9647f16af22a062b07f22331f210dc26f","unresolved":false,"context_lines":[{"line_number":885,"context_line":"            [(\"u1_commit\",)]"},{"line_number":886,"context_line":"        )"},{"line_number":887,"context_line":""},{"line_number":888,"context_line":"    def test_legacy_integration(self):"},{"line_number":889,"context_line":"        legacy_facade \u003d enginefacade.get_legacy_facade()"},{"line_number":890,"context_line":"        self.assertTrue("},{"line_number":891,"context_line":"            legacy_facade.get_engine() is"}],"source_content_type":"text/x-python","patch_set":27,"id":"3a961159_21d72af0","line":888,"in_reply_to":"3a961159_31e41fdf","updated":"2015-01-19 18:38:30.000000000","message":"Done","commit_id":"7c0299ef21b091f26d90ce6a10053c29fca8bd43"}]}
