)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"cf394558d1fb0f7b8afad80ffa79efed55415a28","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"5e3cdec2_e2c57875","updated":"2026-06-11 17:23:06.000000000","message":"recheck","commit_id":"1c682d67c132444f00505c2d4a77f705fe975eba"},{"author":{"_account_id":35133,"name":"Jan Jasek","email":"jjasek@redhat.com","username":"janjasek"},"change_message_id":"a197c20525c5666a1b15e4e613c67097823b09ea","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"68a4c158_10b4588b","updated":"2026-06-25 12:21:51.000000000","message":"LGTM, tested in devstack.\nI think that this Depends-On is not necessary here. I would drop it so this patch is not blocked on an unrelated change.","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"30ae3d1cbdebe26d717d274012d82e040602df06","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"11061e32_baf7f2dd","updated":"2026-06-24 15:01:05.000000000","message":"recheck","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"6f8cceb0f503e597928bb304ba82a2e4af9c9173","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"e6fea0bc_b78925bb","updated":"2026-06-12 17:10:44.000000000","message":"recheck","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":6914,"name":"Tatiana Ovchinnikova","email":"t.v.ovtchinnikova@gmail.com","username":"tmazur"},"change_message_id":"1c65a7f018420b1bd4de7e9077e5dd5101201a8b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"c053e958_9f9aa040","updated":"2026-07-09 13:55:34.000000000","message":"LGTM, thank you!","commit_id":"61239433bcc0c525a3b76beed991414f0efa5de8"},{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"5d59632d090d48028aa56fad91037d22558e1743","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"0f7e0a64_7646dea8","updated":"2026-07-09 05:57:28.000000000","message":"the code looks good, and I have tested it to confirm the message now appears","commit_id":"61239433bcc0c525a3b76beed991414f0efa5de8"}],"openstack_dashboard/dashboards/project/key_pairs/views.py":[{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"a8160865a7fef095a3ff11a20906912a32101c91","unresolved":true,"context_lines":[{"line_number":98,"context_line":"            # so HorizonMiddleware won\u0027t move async messages back into"},{"line_number":99,"context_line":"            # the Django session. Move them manually so they appear on"},{"line_number":100,"context_line":"            # the redirected page after the file download completes."},{"line_number":101,"context_line":"            if hasattr(self.request, \u0027horizon\u0027):"},{"line_number":102,"context_line":"                for tag, msg, extra in self.request.horizon.get("},{"line_number":103,"context_line":"                        \u0027async_messages\u0027, []):"},{"line_number":104,"context_line":"                    getattr(django_messages, tag)("}],"source_content_type":"text/x-python","patch_set":4,"id":"c4cbaa50_14629ce1","line":101,"updated":"2026-06-25 13:49:15.000000000","message":"is there any case where self.request doesn\u0027t have the horizon attribute? when?","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"db82e36a8b8ae65cd7ac5fb5f728da0509e297b7","unresolved":false,"context_lines":[{"line_number":98,"context_line":"            # so HorizonMiddleware won\u0027t move async messages back into"},{"line_number":99,"context_line":"            # the Django session. Move them manually so they appear on"},{"line_number":100,"context_line":"            # the redirected page after the file download completes."},{"line_number":101,"context_line":"            if hasattr(self.request, \u0027horizon\u0027):"},{"line_number":102,"context_line":"                for tag, msg, extra in self.request.horizon.get("},{"line_number":103,"context_line":"                        \u0027async_messages\u0027, []):"},{"line_number":104,"context_line":"                    getattr(django_messages, tag)("}],"source_content_type":"text/x-python","patch_set":4,"id":"5b74d033_d4b25c6c","line":101,"in_reply_to":"a28c5708_df3a1621","updated":"2026-07-08 19:20:30.000000000","message":"Done","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"c2a95fd48ff40094f0386f282a612977e7736736","unresolved":true,"context_lines":[{"line_number":98,"context_line":"            # so HorizonMiddleware won\u0027t move async messages back into"},{"line_number":99,"context_line":"            # the Django session. Move them manually so they appear on"},{"line_number":100,"context_line":"            # the redirected page after the file download completes."},{"line_number":101,"context_line":"            if hasattr(self.request, \u0027horizon\u0027):"},{"line_number":102,"context_line":"                for tag, msg, extra in self.request.horizon.get("},{"line_number":103,"context_line":"                        \u0027async_messages\u0027, []):"},{"line_number":104,"context_line":"                    getattr(django_messages, tag)("}],"source_content_type":"text/x-python","patch_set":4,"id":"a28c5708_df3a1621","line":101,"in_reply_to":"c4cbaa50_14629ce1","updated":"2026-07-08 19:19:54.000000000","message":"I could not find other places that check for the `horizon` attribute before using it, or checking for `async_messages`.\n\nIf we can assume that all authenticated requests go through `_process_request()` as part of the middleware stack, then the `horizon` attribute always gets defined, as well as `async_messages`:\n\nhttps://github.com/openstack/horizon/blob/master/horizon/middleware/base.py#L60\n\n    def _process_request(self, request):\n        \"\"\"Adds data necessary for Horizon to function to the request.\"\"\"\n\n        request.horizon \u003d {\u0027dashboard\u0027: None,\n                           \u0027panel\u0027: None,\n                           \u0027async_messages\u0027: []}\n\n**A few thoughts:**\n- It does not hurt to have this check. Keep the check \"just in case\" we missed something?\n- Or, remove it, based on my analysis that the `horizon` attribute should always be set properly.\n\n**I am leaning towards removing it (as I just did)**\n\nLet me know your thoughts.\n\n**As an fyi** - I found another place where we directly access `request.horizon[\u0027async_messages\u0027]` without a check:\n\nhttps://github.com/openstack/horizon/blob/master/horizon/messages.py\n\n    def horizon_message_already_queued(request, message):\n        _message \u003d force_str(message)\n        if http_utils.is_ajax(request):\n            for tag, msg, extra in request.horizon[\u0027async_messages\u0027]:\n                if _message \u003d\u003d msg:\n                    return True\n        else:\n            for msg in _messages.get_messages(request)._queued_messages:\n                if msg.message \u003d\u003d _message:\n                    return True\n        return False","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":8648,"name":"Radomir Dopieralski","email":"openstack@dopieralski.pl","username":"thesheep"},"change_message_id":"a8160865a7fef095a3ff11a20906912a32101c91","unresolved":true,"context_lines":[{"line_number":100,"context_line":"            # the redirected page after the file download completes."},{"line_number":101,"context_line":"            if hasattr(self.request, \u0027horizon\u0027):"},{"line_number":102,"context_line":"                for tag, msg, extra in self.request.horizon.get("},{"line_number":103,"context_line":"                        \u0027async_messages\u0027, []):"},{"line_number":104,"context_line":"                    getattr(django_messages, tag)("},{"line_number":105,"context_line":"                        self.request, msg, extra)"},{"line_number":106,"context_line":"                self.request.horizon[\u0027async_messages\u0027] \u003d []"}],"source_content_type":"text/x-python","patch_set":4,"id":"ad58f315_07055ad8","line":103,"updated":"2026-06-25 13:49:15.000000000","message":"is there any case where there is self.request.horizon but it doesn\u0027t have async_messages? when?","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"db82e36a8b8ae65cd7ac5fb5f728da0509e297b7","unresolved":false,"context_lines":[{"line_number":100,"context_line":"            # the redirected page after the file download completes."},{"line_number":101,"context_line":"            if hasattr(self.request, \u0027horizon\u0027):"},{"line_number":102,"context_line":"                for tag, msg, extra in self.request.horizon.get("},{"line_number":103,"context_line":"                        \u0027async_messages\u0027, []):"},{"line_number":104,"context_line":"                    getattr(django_messages, tag)("},{"line_number":105,"context_line":"                        self.request, msg, extra)"},{"line_number":106,"context_line":"                self.request.horizon[\u0027async_messages\u0027] \u003d []"}],"source_content_type":"text/x-python","patch_set":4,"id":"7494900e_d09dc08b","line":103,"in_reply_to":"9a5d993f_fe1eb30c","updated":"2026-07-08 19:20:30.000000000","message":"Done","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"},{"author":{"_account_id":32432,"name":"Owen McGonagle","email":"omcgonag@redhat.com","username":"omcgonag"},"change_message_id":"c2a95fd48ff40094f0386f282a612977e7736736","unresolved":true,"context_lines":[{"line_number":100,"context_line":"            # the redirected page after the file download completes."},{"line_number":101,"context_line":"            if hasattr(self.request, \u0027horizon\u0027):"},{"line_number":102,"context_line":"                for tag, msg, extra in self.request.horizon.get("},{"line_number":103,"context_line":"                        \u0027async_messages\u0027, []):"},{"line_number":104,"context_line":"                    getattr(django_messages, tag)("},{"line_number":105,"context_line":"                        self.request, msg, extra)"},{"line_number":106,"context_line":"                self.request.horizon[\u0027async_messages\u0027] \u003d []"}],"source_content_type":"text/x-python","patch_set":4,"id":"9a5d993f_fe1eb30c","line":103,"in_reply_to":"ad58f315_07055ad8","updated":"2026-07-08 19:19:54.000000000","message":"see above","commit_id":"8df84e10a17d1b0ec65e838005a0a420677c799d"}]}
