)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"358bbf4b31049ac8bdd35bc63c89667ae396bf21","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"9c8f1d15_9b4fe91e","updated":"2025-08-19 14:34:48.000000000","message":"+1: at first look it is in a good shape. Thanks for the hard work","commit_id":"b42992c0853f75349af20040d804f31a6e4ad9f3"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"a2e6f1aed4e2c9baa7fdfc37affc01407db4d369","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"71db8f9b_7109faf2","updated":"2025-08-20 10:03:46.000000000","message":"lgtm, thanks Alfredo","commit_id":"84e739fb23bdb87605223651380198610724b063"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"31a604d6ef98f46f0e97e9af9a542c1b25db3ae3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"013d70ed_b67b770d","updated":"2025-08-26 12:14:17.000000000","message":"Lets move forward and add any other fix needed in the follow up patch[1]\nThanks Alfredo!\n\n[1] https://review.opendev.org/c/openstack/watcher/+/958469","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"6a03b1ad_b4341e5e","updated":"2025-08-21 16:11:09.000000000","message":"there are quite a few thing that annoy me in this patch that i would normally ask to be changed.\n\nlet me check with doug on howe we want to proceed. and if we want to file bugs to adress thing in followup, if we want to respin or if we just want to keep the bluepitn open for another week and fix the issues using that as the tracker.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"963062ee488e36d75fd02d46bf9fb034992769dc","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"5e5cdc38_a9f58a99","updated":"2025-08-21 15:48:57.000000000","message":"this LGTM, no concerns with this implementation. It matches with the proposed spec.\nThank","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"625562af701fbcd22503388c34cd3cf23bbdb669","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"0b2e135f_a4131bdc","updated":"2025-08-26 12:01:44.000000000","message":"upgradign to +2 based on followup","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"}],"api-ref/source/watcher-api-v1-actions.inc":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":false,"context_lines":[{"line_number":171,"context_line":"    an Action Plan in RECOMMENDED or PENDING state. This operation requires"},{"line_number":172,"context_line":"    API microversion 1.5 or later."},{"line_number":173,"context_line":""},{"line_number":174,"context_line":"Normal response codes: 200"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"Error codes: 400,404,403,409"},{"line_number":177,"context_line":""}],"source_content_type":"text/x-c++src","patch_set":5,"id":"affd9c88_019f533c","line":174,"range":{"start_line":174,"start_character":23,"end_line":174,"end_character":26},"updated":"2025-08-21 16:11:09.000000000","message":"200 is ok but its actully an intersting question fi it shoudl be a 202\n\nif the action plan is pending i.e. we have accpated it but it has not been executed this is techinaly a rece with teh applier and the skip is techninally asyc however\nwe are directly udating the db before we return synconosly.\n\nim pretty sure 200 is what we agreed in the spec but since we currently have not agreed to refacto this into an RPC call either would have been correct.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"}],"watcher/api/controllers/rest_api_version_history.rst":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"358bbf4b31049ac8bdd35bc63c89667ae396bf21","unresolved":true,"context_lines":[{"line_number":43,"context_line":"1.5"},{"line_number":44,"context_line":"---"},{"line_number":45,"context_line":"Added support for SKIPPED actions status via PATCH support for Actions API"},{"line_number":46,"context_line":"and automatic condition detection in pre_condition. This feature also"},{"line_number":47,"context_line":"introduces the ``status_message`` field to audits, actions and action plans."}],"source_content_type":"text/x-rst","patch_set":3,"id":"00842d9b_8240a2d4","line":46,"range":{"start_line":46,"start_character":0,"end_line":46,"end_character":50},"updated":"2025-08-19 14:34:48.000000000","message":"nit: i think we can omit the pre_condition part, since is not related to the api.","commit_id":"b42992c0853f75349af20040d804f31a6e4ad9f3"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"8b1b954964510b9b13789b9493d69cb534c68b71","unresolved":false,"context_lines":[{"line_number":43,"context_line":"1.5"},{"line_number":44,"context_line":"---"},{"line_number":45,"context_line":"Added support for SKIPPED actions status via PATCH support for Actions API"},{"line_number":46,"context_line":"and automatic condition detection in pre_condition. This feature also"},{"line_number":47,"context_line":"introduces the ``status_message`` field to audits, actions and action plans."}],"source_content_type":"text/x-rst","patch_set":3,"id":"94d712d6_f4a31da7","line":46,"range":{"start_line":46,"start_character":0,"end_line":46,"end_character":50},"in_reply_to":"00842d9b_8240a2d4","updated":"2025-08-20 11:14:20.000000000","message":"Done","commit_id":"b42992c0853f75349af20040d804f31a6e4ad9f3"}],"watcher/api/controllers/v1/action.py":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"358bbf4b31049ac8bdd35bc63c89667ae396bf21","unresolved":false,"context_lines":[{"line_number":417,"context_line":"            raise exception.PatchError(patch\u003dpatch, reason\u003de)"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        # Define allowed state transitions for actions"},{"line_number":420,"context_line":"        allowed_patch_transitions \u003d ["},{"line_number":421,"context_line":"            (objects.action.State.PENDING, objects.action.State.SKIPPED),"},{"line_number":422,"context_line":"        ]"},{"line_number":423,"context_line":""},{"line_number":424,"context_line":"        # Validate state transitions if state is being modified"},{"line_number":425,"context_line":"        if hasattr(action, \u0027state\u0027) and action.state !\u003d action_to_update.state:"}],"source_content_type":"text/x-python","patch_set":3,"id":"188d7066_e49820ca","line":422,"range":{"start_line":420,"start_character":0,"end_line":422,"end_character":9},"updated":"2025-08-19 14:34:48.000000000","message":"+1","commit_id":"b42992c0853f75349af20040d804f31a6e4ad9f3"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"358bbf4b31049ac8bdd35bc63c89667ae396bf21","unresolved":false,"context_lines":[{"line_number":433,"context_line":"                        initial_state\u003daction_to_update.state,"},{"line_number":434,"context_line":"                        new_state\u003daction.state))"},{"line_number":435,"context_line":"            action_plan \u003d action_to_update.action_plan"},{"line_number":436,"context_line":"            if action_plan.state not in [objects.action_plan.State.RECOMMENDED,"},{"line_number":437,"context_line":"                                         objects.action_plan.State.PENDING]:"},{"line_number":438,"context_line":"                error_message \u003d _(\"State update not allowed for actionplan \""},{"line_number":439,"context_line":"                                  \"state: %(ap_state)s\")"},{"line_number":440,"context_line":"                raise exception.Conflict("}],"source_content_type":"text/x-python","patch_set":3,"id":"a868cf60_572c7d02","line":437,"range":{"start_line":436,"start_character":0,"end_line":437,"end_character":76},"updated":"2025-08-19 14:34:48.000000000","message":"+1","commit_id":"b42992c0853f75349af20040d804f31a6e4ad9f3"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":113,"context_line":"    def allowed_attrs():"},{"line_number":114,"context_line":"        return [\"/state\", \"/status_message\"]"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"    @staticmethod"},{"line_number":117,"context_line":"    def internal_attrs():"},{"line_number":118,"context_line":"        return types.JsonPatchType.internal_attrs()"},{"line_number":119,"context_line":""},{"line_number":120,"context_line":"    # We do not allow to remove any attribute via PATCH so setting all fields"},{"line_number":121,"context_line":"    # as mandatory"}],"source_content_type":"text/x-python","patch_set":5,"id":"ef4ef41a_2340f1eb","line":118,"range":{"start_line":116,"start_character":0,"end_line":118,"end_character":51},"updated":"2025-08-21 16:11:09.000000000","message":"nit if its just the same as the default we don\u0027t need to define it.\n\nits also more correct for this to be a class methodn not a static one.\n\n\nthe same is true of the other for that its worth they woudl be more correct as class methods.\n\nespically since validate does  ActionPatchType._validate_state(patch)\n\ni think we can adress this in a diffent foollow up form the rest of my comments.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":422,"context_line":"        ]"},{"line_number":423,"context_line":""},{"line_number":424,"context_line":"        # Validate state transitions if state is being modified"},{"line_number":425,"context_line":"        if hasattr(action, \u0027state\u0027) and action.state !\u003d action_to_update.state:"},{"line_number":426,"context_line":"            transition \u003d (action_to_update.state, action.state)"},{"line_number":427,"context_line":"            if transition not in allowed_patch_transitions:"},{"line_number":428,"context_line":"                error_message \u003d _(\"State transition not allowed: \""}],"source_content_type":"text/x-python","patch_set":5,"id":"2676f3e9_1f6be755","line":425,"range":{"start_line":425,"start_character":11,"end_line":425,"end_character":35},"updated":"2025-08-21 16:11:09.000000000","message":"this could be `\u0027state\u0027 in action_dict`\n\nusage of hasstr or the other associate function is a general code smell.\n\nyou are reach for a very primitive/lowlevel function and it almost alwasy a sign of purly designed types.\n\nout side of test code we shoudl try to minimise ti usage.\n\nbeyond the fact that its error prone it makes liniting and static always harder.\n\nyou are following the convetion in this file but this is one ot the reason i evenutlaly want to remove all usage fo wsme although its not the main one.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"31a604d6ef98f46f0e97e9af9a542c1b25db3ae3","unresolved":true,"context_lines":[{"line_number":422,"context_line":"        ]"},{"line_number":423,"context_line":""},{"line_number":424,"context_line":"        # Validate state transitions if state is being modified"},{"line_number":425,"context_line":"        if hasattr(action, \u0027state\u0027) and action.state !\u003d action_to_update.state:"},{"line_number":426,"context_line":"            transition \u003d (action_to_update.state, action.state)"},{"line_number":427,"context_line":"            if transition not in allowed_patch_transitions:"},{"line_number":428,"context_line":"                error_message \u003d _(\"State transition not allowed: \""}],"source_content_type":"text/x-python","patch_set":5,"id":"f9f11ea4_826c1e63","line":425,"range":{"start_line":425,"start_character":11,"end_line":425,"end_character":35},"in_reply_to":"2676f3e9_1f6be755","updated":"2025-08-26 12:14:17.000000000","message":"Ack. Checking the code with more time, I can see that both \u0027action_to_update\u0027 (from object.Action) and \u0027action\u0027 (from api Action class) have \u0027state\u0027 as a mandatory field and exposed param, so we don\u0027t actually need to double check that \u0027action\u0027 has a state attribute. And the transition check below will guarantee that we don\u0027t move to an invalid change in the state.  We should be fine just comparing.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"}],"watcher/common/policies/action.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":61,"context_line":"            }"},{"line_number":62,"context_line":"        ]"},{"line_number":63,"context_line":"    )"},{"line_number":64,"context_line":"]"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"def list_rules():"}],"source_content_type":"text/x-python","patch_set":5,"id":"cc9dda9c_6b1face9","line":64,"updated":"2025-08-21 16:11:09.000000000","message":"+1\n\ni tought you missed this for a second but i skip the file on my first reveiw","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"}],"watcher/tests/api/v1/test_actions.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":67,"context_line":"        for field in action_fields:"},{"line_number":68,"context_line":"            self.assertIn(field, action)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    def test_one(self):"},{"line_number":71,"context_line":"        action \u003d obj_utils.create_test_action(self.context, parents\u003dNone)"},{"line_number":72,"context_line":"        response \u003d self.get_json(\u0027/actions\u0027)"},{"line_number":73,"context_line":"        self.assertEqual(action.uuid, response[\u0027actions\u0027][0][\"uuid\"])"},{"line_number":74,"context_line":"        self._assert_action_fields(response[\u0027actions\u0027][0])"},{"line_number":75,"context_line":"        self.assertNotIn(\u0027status_message\u0027, response[\u0027actions\u0027][0])"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"    def test_one_with_status_message(self):"},{"line_number":78,"context_line":"        action \u003d obj_utils.create_test_action("},{"line_number":79,"context_line":"            self.context, parents\u003dNone, status_message\u003d\u0027Fake message\u0027)"},{"line_number":80,"context_line":"        response \u003d self.get_json("}],"source_content_type":"text/x-python","patch_set":5,"id":"32459c7d_f37eda1d","line":77,"range":{"start_line":70,"start_character":4,"end_line":77,"end_character":43},"updated":"2025-08-21 16:11:09.000000000","message":"thse shoudl be be test_list not test 1","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"31a604d6ef98f46f0e97e9af9a542c1b25db3ae3","unresolved":false,"context_lines":[{"line_number":67,"context_line":"        for field in action_fields:"},{"line_number":68,"context_line":"            self.assertIn(field, action)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    def test_one(self):"},{"line_number":71,"context_line":"        action \u003d obj_utils.create_test_action(self.context, parents\u003dNone)"},{"line_number":72,"context_line":"        response \u003d self.get_json(\u0027/actions\u0027)"},{"line_number":73,"context_line":"        self.assertEqual(action.uuid, response[\u0027actions\u0027][0][\"uuid\"])"},{"line_number":74,"context_line":"        self._assert_action_fields(response[\u0027actions\u0027][0])"},{"line_number":75,"context_line":"        self.assertNotIn(\u0027status_message\u0027, response[\u0027actions\u0027][0])"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"    def test_one_with_status_message(self):"},{"line_number":78,"context_line":"        action \u003d obj_utils.create_test_action("},{"line_number":79,"context_line":"            self.context, parents\u003dNone, status_message\u003d\u0027Fake message\u0027)"},{"line_number":80,"context_line":"        response \u003d self.get_json("}],"source_content_type":"text/x-python","patch_set":5,"id":"8d321161_35324bd9","line":77,"range":{"start_line":70,"start_character":4,"end_line":77,"end_character":43},"in_reply_to":"32459c7d_f37eda1d","updated":"2025-08-26 12:14:17.000000000","message":"Acknowledged","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":103,"context_line":"        self.assertEqual("},{"line_number":104,"context_line":"            \u0027Fake message\u0027, response[\u0027actions\u0027][0][\"status_message\"])"},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"    def test_one_soft_deleted(self):"},{"line_number":107,"context_line":"        action \u003d obj_utils.create_test_action(self.context, parents\u003dNone)"},{"line_number":108,"context_line":"        action.soft_delete()"},{"line_number":109,"context_line":"        response \u003d self.get_json(\u0027/actions\u0027,"}],"source_content_type":"text/x-python","patch_set":5,"id":"bcff4744_f3c2bd74","line":106,"range":{"start_line":106,"start_character":8,"end_line":106,"end_character":29},"updated":"2025-08-21 16:11:09.000000000","message":"this is also test_list_soft_delted","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":114,"context_line":"        response \u003d self.get_json(\u0027/actions\u0027)"},{"line_number":115,"context_line":"        self.assertEqual([], response[\u0027actions\u0027])"},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"    def test_get_one(self):"},{"line_number":118,"context_line":"        action \u003d obj_utils.create_test_action(self.context, parents\u003dNone)"},{"line_number":119,"context_line":"        response \u003d self.get_json(\u0027/actions/%s\u0027 % action[\u0027uuid\u0027])"},{"line_number":120,"context_line":"        self.assertEqual(action.uuid, response[\u0027uuid\u0027])"}],"source_content_type":"text/x-python","patch_set":5,"id":"14429b27_d95c733a","line":117,"range":{"start_line":117,"start_character":8,"end_line":117,"end_character":20},"updated":"2025-08-21 16:11:09.000000000","message":"and this is really test_show\n\n\nthese name change are seperate form this patch but we shoudl real fix them and the actul function they test in the future to follow the normal naming convetions.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":528,"context_line":""},{"line_number":529,"context_line":"    def setUp(self):"},{"line_number":530,"context_line":"        super(TestPatchAction, self).setUp()"},{"line_number":531,"context_line":"        obj_utils.create_test_goal(self.context)"},{"line_number":532,"context_line":"        obj_utils.create_test_strategy(self.context)"},{"line_number":533,"context_line":"        obj_utils.create_test_audit(self.context)"},{"line_number":534,"context_line":"        self.action_plan \u003d obj_utils.create_test_action_plan("},{"line_number":535,"context_line":"            self.context,"},{"line_number":536,"context_line":"            state\u003dobjects.action_plan.State.PENDING)"}],"source_content_type":"text/x-python","patch_set":5,"id":"c0580c91_17fefe52","line":533,"range":{"start_line":531,"start_character":0,"end_line":533,"end_character":49},"updated":"2025-08-21 16:11:09.000000000","message":"thise return teh object\nyou need to assign them to self or a var to use them properly.\n\n\nyour tests are not actully using this they are usign the one form line 56\n\nhttps://review.opendev.org/c/openstack/watcher/+/955753/5/watcher/tests/api/v1/test_actions.py#56","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":533,"context_line":"        obj_utils.create_test_audit(self.context)"},{"line_number":534,"context_line":"        self.action_plan \u003d obj_utils.create_test_action_plan("},{"line_number":535,"context_line":"            self.context,"},{"line_number":536,"context_line":"            state\u003dobjects.action_plan.State.PENDING)"},{"line_number":537,"context_line":"        self.action \u003d obj_utils.create_test_action(self.context, parents\u003dNone)"},{"line_number":538,"context_line":"        p \u003d mock.patch.object(db_api.BaseConnection, \u0027update_action\u0027)"},{"line_number":539,"context_line":"        self.mock_action_update \u003d p.start()"}],"source_content_type":"text/x-python","patch_set":5,"id":"cdde2606_390f5c0e","line":536,"updated":"2025-08-21 16:11:09.000000000","message":"you assgined this properly :)","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f07492c9b15523e9cbbe35ffb202a59c2117d9e5","unresolved":true,"context_lines":[{"line_number":535,"context_line":"            self.context,"},{"line_number":536,"context_line":"            state\u003dobjects.action_plan.State.PENDING)"},{"line_number":537,"context_line":"        self.action \u003d obj_utils.create_test_action(self.context, parents\u003dNone)"},{"line_number":538,"context_line":"        p \u003d mock.patch.object(db_api.BaseConnection, \u0027update_action\u0027)"},{"line_number":539,"context_line":"        self.mock_action_update \u003d p.start()"},{"line_number":540,"context_line":"        self.mock_action_update.side_effect \u003d self._simulate_rpc_action_update"},{"line_number":541,"context_line":"        self.addCleanup(p.stop)"},{"line_number":542,"context_line":""},{"line_number":543,"context_line":"    def _simulate_rpc_action_update(self, action):"},{"line_number":544,"context_line":"        action.save()"}],"source_content_type":"text/x-python","patch_set":5,"id":"af9906c9_a16a8e1f","line":541,"range":{"start_line":538,"start_character":0,"end_line":541,"end_character":31},"updated":"2025-08-21 16:11:09.000000000","message":"this is also usign the patten that we started removing \n\nthe correct way to do this is via the fixtures lib like this\n\nhttps://review.opendev.org/c/openstack/watcher/+/952538/14/watcher/tests/applier/actions/test_stop.py#34\n\n```\n        p \u003d mock.patch.object(db_api.BaseConnection, \u0027update_action\u0027)\n        self.mock_action_update \u003d p.start()\n        self.mock_action_update.side_effect \u003d self._simulate_rpc_action_update\n        self.addCleanup(p.stop)\n```\n\nbecomes this\n\n```\nself.mock_action_update \u003d self.useFixture(\n    fixtures.MockPatchObject(\n        db_api.BaseConnection, \"update_action\",\n        autospec\u003dFalse,  side_effect\u003dself._simulate_rpc_action_update)).mock\n\n```\n\nits often shorter and much less error prone as you cant forget to start/stop the mock.","commit_id":"e06f1b0475b1544902d8f0f03faca1abcfcc5dce"}]}
