)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":1,"id":"ee76574e_ffb63baf","updated":"2025-12-16 09:09:58.000000000","message":"I see that mypy on the gate fails with\n```\nnova/utils.py:133: error: Unused \"type: ignore\" comment  [unused-ignore]\nnova/utils.py:1312: error: Unused \"type: ignore\" comment  [unused-ignore]\nnova/utils.py:1350: error: Unused \"type: ignore\" comment  [unused-ignore]\nFound 3 errors in 1 file (checked 31 source files)\n```\nbut locally if I remove those \"type: ignore\" comments then I get \n```\nnova/utils.py: note: In function \"_get_default_executor\":\nnova/utils.py:132:9: error: Item \"None\" of \"Any | Any | None\" has no attribute \"name\"  [union-attr]\nFound 1 error in 1 file (checked 31 source files)\n```\n@stephenfin@redhat.com Do you have any idea why the local run differs from the gate run?","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"f538255e_5d98ceb4","updated":"2025-12-08 18:04:03.000000000","message":"Thanks for doing this 🙏 I left a few comments inline to modernise them a small bit and add some of the missing hints. Please feel free to ignore ofc.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"64ab41430ef1eacd4e40ce170fd07a6c5c8cb307","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"0560ed1a_c399aa02","in_reply_to":"b663dce5_a80a9fc4","updated":"2025-12-19 16:05:28.000000000","message":"thanks clean solved it.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"65d3a1f8c70273f035bd48e9d3e0717121551401","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":1,"id":"b663dce5_a80a9fc4","in_reply_to":"ee76574e_ffb63baf","updated":"2025-12-16 15:12:54.000000000","message":"That\u0027s happening because your (cached) pre-commit env has different versions of the dependencies to the (newly create) env the gate is using. You can fix this with `pre-commit clean`, however, I\u0027ve come to the conclusion that pre-commit is the wrong tool for this job and [have been migrating off of it for other projects](https://review.opendev.org/q/%22Run+mypy+from+tox%22). I suspect we want to do the same here, and in fact I have a local patch to do just that.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8c8db4d66a9ecabd30d59c844f4513dfc464985a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"0d82c9fb_feace667","updated":"2026-02-03 14:03:11.000000000","message":"@stephenfin@redhat.com\u0027s comments could be a follow-up","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"db59ec41_9c89b432","updated":"2026-01-29 11:49:32.000000000","message":"Looking good. I left a few notes inline. Feel free to ignore since I\u0027m addressing all of these (bar the new code added in this stack, obv) [here](https://review.opendev.org/c/openstack/nova/+/705658).","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"fb260410a0d8e4e9ecbebe5402196d3b44a78d93","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"f7f3995e_bbb2d86e","updated":"2026-02-04 20:34:22.000000000","message":"i agree with stephens suggestions\nim also ok with those being adressed in a followup.\n\nso +2 becuase i think its more imporant to move forward with the eventlet remvoeal\nbut also do think the enhacments stephen suggested makes sense to do in a later patch.","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"d43810412600c966abe7a3f527eba43e5937bdee","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"f8aadbe0_d678ae90","in_reply_to":"0d82c9fb_feace667","updated":"2026-02-04 09:18:56.000000000","message":"Yeah I\u0027m planning for a follow up","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"487a7bc87df0f81fb99559a775b747d2d641766f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"8f434535_3ce2029b","in_reply_to":"db59ec41_9c89b432","updated":"2026-01-29 11:50:10.000000000","message":"Just to rephrase that, the notes are left in case they\u0027re of interest, not because I expect you to apply them","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"ac6909a339eaa066d8f18d5220b752aa8db70677","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"c368b1b8_1ab23816","in_reply_to":"f7f3995e_bbb2d86e","updated":"2026-02-05 01:14:48.000000000","message":"indeed, let\u0027s proceed on eventlet-removal and stephen suggestion can be done in later change.","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"}],"nova/utils.py":[{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":75,"context_line":"    \u0027img_mappings\u0027, \u0027img_block_device_mapping\u0027,"},{"line_number":76,"context_line":")"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"_FILE_CACHE: ty.Dict[str, ty.Dict] \u003d {}"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"_SERVICE_TYPES \u003d service_types.ServiceTypes()"},{"line_number":81,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"d6c9b3b4_6c65b258","line":78,"updated":"2025-12-08 18:04:03.000000000","message":"We only support Python 3.10+ now so you could just do:\n\n```suggestion\n_FILE_CACHE: dict[str, dict] \u003d {}\n```\n\nI think the typing aliases are deprecated for removal at some point (though not anytime soon tbf)","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    \u0027img_mappings\u0027, \u0027img_block_device_mapping\u0027,"},{"line_number":76,"context_line":")"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"_FILE_CACHE: ty.Dict[str, ty.Dict] \u003d {}"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"_SERVICE_TYPES \u003d service_types.ServiceTypes()"},{"line_number":81,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"f4db23a5_d88a0b7a","line":78,"in_reply_to":"d6c9b3b4_6c65b258","updated":"2025-12-16 09:09:58.000000000","message":"Done","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"# NOTE(gibi): futurist does not expose the common based class."},{"line_number":83,"context_line":"# NOTE(gibi): we can simplify this when eventlet is removed."},{"line_number":84,"context_line":"Executor \u003d ty.Union["},{"line_number":85,"context_line":"    futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor]"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"DEFAULT_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def cooperative_yield():"}],"source_content_type":"text/x-python","patch_set":1,"id":"e42e94a2_871fb90b","line":87,"range":{"start_line":84,"start_character":0,"end_line":87,"end_character":46},"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\nExecutor \u003d futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor\n\nDEFAULT_EXECUTOR: Executor | None \u003d None\n```","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"65d3a1f8c70273f035bd48e9d3e0717121551401","unresolved":true,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"# NOTE(gibi): futurist does not expose the common based class."},{"line_number":83,"context_line":"# NOTE(gibi): we can simplify this when eventlet is removed."},{"line_number":84,"context_line":"Executor \u003d ty.Union["},{"line_number":85,"context_line":"    futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor]"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"DEFAULT_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def cooperative_yield():"}],"source_content_type":"text/x-python","patch_set":1,"id":"e9dcb21a_31016b39","line":87,"range":{"start_line":84,"start_character":0,"end_line":87,"end_character":46},"in_reply_to":"afc8c1ee_8c7173fe","updated":"2025-12-16 15:12:54.000000000","message":"Very odd. That usually only happens when you\u0027re trying to use a (dynamic) variable as a type. How about if you explicitly declare this as a TypeAlias?\n\n```\nExecutor: ty.TypeAlias \u003d (\n  futurist.GreenThreadPoolExecutor |\n  futurist.ThreadPoolExecutor)\nDEFAULT_EXECUTOR: Executor | None \u003d None\n```\n\nAs an aside, it probably would be good to add a base class or protocol to `futurist` that we could use. Not your job though","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":true,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"# NOTE(gibi): futurist does not expose the common based class."},{"line_number":83,"context_line":"# NOTE(gibi): we can simplify this when eventlet is removed."},{"line_number":84,"context_line":"Executor \u003d ty.Union["},{"line_number":85,"context_line":"    futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor]"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"DEFAULT_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def cooperative_yield():"}],"source_content_type":"text/x-python","patch_set":1,"id":"afc8c1ee_8c7173fe","line":87,"range":{"start_line":84,"start_character":0,"end_line":87,"end_character":46},"in_reply_to":"e42e94a2_871fb90b","updated":"2025-12-16 09:09:58.000000000","message":"I tried to drop the ty.Union before but it fails for me with\n\n```\nmypy.....................................................................Failed\n- hook id: mypy\n- exit code: 1\n\nnova/utils.py:86:31: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:86:31: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: In function \"create_executor\":\nnova/utils.py:112:37: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:112:37: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: In function \"_get_default_executor\":\nnova/utils.py:120:32: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:120:32: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: In function \"_executor_is_full\":\nnova/utils.py:608:33: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:608:33: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py:612:14: error: Executor? has no attribute \"_shutdown_lock\"  [attr-defined]\nnova/utils.py:613:44: error: Executor? has no attribute \"_workers\"  [attr-defined]\nnova/utils.py:614:28: error: Executor? has no attribute \"_work_queue\"  [attr-defined]\nnova/utils.py: note: In function \"spawn_on\":\nnova/utils.py:621:15: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:621:15: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py:637:22: error: Executor? has no attribute \"name\"  [attr-defined]\nnova/utils.py:638:26: error: Executor? has no attribute \"submit\"  [attr-defined]\nnova/utils.py: note: At top level:\nnova/utils.py:1193:38: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:1193:38: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: In function \"get_scatter_gather_executor\":\nnova/utils.py:1196:38: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:1196:38: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: At top level:\nnova/utils.py:1234:36: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:1234:36: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: In function \"get_cache_images_executor\":\nnova/utils.py:1237:36: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:1237:36: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py: note: In function \"_log_executor_stats\":\nnova/utils.py:1271:35: error: Variable \"nova.utils.Executor\" is not valid as a type  [valid-type]\nnova/utils.py:1271:35: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases\nnova/utils.py:1282:5: error: Executor? has no attribute \"last_stats\"  [attr-defined]\nnova/utils.py:1284:42: error: Executor? has no attribute \"statistics\"  [attr-defined]\nFound 17 errors in 1 file (checked 31 source files)\n\n```\n\nbtw, \"|\" within ty.Union is a mistake, I\u0027m fixing in respin.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"64ab41430ef1eacd4e40ce170fd07a6c5c8cb307","unresolved":false,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"# NOTE(gibi): futurist does not expose the common based class."},{"line_number":83,"context_line":"# NOTE(gibi): we can simplify this when eventlet is removed."},{"line_number":84,"context_line":"Executor \u003d ty.Union["},{"line_number":85,"context_line":"    futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor]"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"DEFAULT_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def cooperative_yield():"}],"source_content_type":"text/x-python","patch_set":1,"id":"48896a48_24ef818c","line":87,"range":{"start_line":84,"start_character":0,"end_line":87,"end_character":46},"in_reply_to":"e9dcb21a_31016b39","updated":"2025-12-19 16:05:28.000000000","message":"typealias worked thanks.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":592,"context_line":"    return runner(context_wrapper, *args, **kwargs)"},{"line_number":593,"context_line":""},{"line_number":594,"context_line":""},{"line_number":595,"context_line":"def spawn(func: ty.Callable, *args, **kwargs) -\u003e futurist.Future:"},{"line_number":596,"context_line":"    \"\"\"Passthrough method for eventlet.spawn."},{"line_number":597,"context_line":""},{"line_number":598,"context_line":"    This utility exists so that it can be stubbed for testing without"}],"source_content_type":"text/x-python","patch_set":1,"id":"d9beecd7_134cf4ee","line":595,"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\ndef spawn(\n    func: ty.Callable[..., ty.Any], *args: Any, **kwargs: Any,\n) -\u003e futurist.Future:\n```","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":false,"context_lines":[{"line_number":592,"context_line":"    return runner(context_wrapper, *args, **kwargs)"},{"line_number":593,"context_line":""},{"line_number":594,"context_line":""},{"line_number":595,"context_line":"def spawn(func: ty.Callable, *args, **kwargs) -\u003e futurist.Future:"},{"line_number":596,"context_line":"    \"\"\"Passthrough method for eventlet.spawn."},{"line_number":597,"context_line":""},{"line_number":598,"context_line":"    This utility exists so that it can be stubbed for testing without"}],"source_content_type":"text/x-python","patch_set":1,"id":"8f89318d_e8d6514e","line":595,"in_reply_to":"d9beecd7_134cf4ee","updated":"2025-12-16 09:09:58.000000000","message":"Done","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":620,"context_line":""},{"line_number":621,"context_line":"def spawn_on("},{"line_number":622,"context_line":"    executor: Executor,"},{"line_number":623,"context_line":"    func: ty.Callable,"},{"line_number":624,"context_line":"    *args, **kwargs"},{"line_number":625,"context_line":") -\u003e futurist.Future:"},{"line_number":626,"context_line":"    \"\"\"Passthrough method to run func on a thread in a given executor."},{"line_number":627,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"b73ff65f_2aaa0e8d","line":624,"range":{"start_line":623,"start_character":0,"end_line":624,"end_character":19},"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\n    func: ty.Callable[..., ty.Any],\n    *args: ty.Any,\n    **kwargs: ty.Any,\n```","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":false,"context_lines":[{"line_number":620,"context_line":""},{"line_number":621,"context_line":"def spawn_on("},{"line_number":622,"context_line":"    executor: Executor,"},{"line_number":623,"context_line":"    func: ty.Callable,"},{"line_number":624,"context_line":"    *args, **kwargs"},{"line_number":625,"context_line":") -\u003e futurist.Future:"},{"line_number":626,"context_line":"    \"\"\"Passthrough method to run func on a thread in a given executor."},{"line_number":627,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"0efde097_689b929c","line":624,"range":{"start_line":623,"start_character":0,"end_line":624,"end_character":19},"in_reply_to":"b73ff65f_2aaa0e8d","updated":"2025-12-16 09:09:58.000000000","message":"Done","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":639,"context_line":"    return _pass_context(executor.submit, func, *args, **kwargs)"},{"line_number":640,"context_line":""},{"line_number":641,"context_line":""},{"line_number":642,"context_line":"def tpool_execute(func: ty.Callable, *args, **kwargs):"},{"line_number":643,"context_line":"    \"\"\"Run func in a native thread\"\"\""},{"line_number":644,"context_line":"    return _pass_context(tpool.execute, func, *args, **kwargs)"},{"line_number":645,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"3bca9731_fac47dbc","line":642,"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\ndef tpool_execute(\n    func: ty.Callable[..., ty.Any],\n    *args: ty.Any,\n    **kwargs: ty.Any,\n) -\u003e futurist.Future:\n```\n\nNote that I\u0027m guessing the return type there. It might be wrong.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":true,"context_lines":[{"line_number":639,"context_line":"    return _pass_context(executor.submit, func, *args, **kwargs)"},{"line_number":640,"context_line":""},{"line_number":641,"context_line":""},{"line_number":642,"context_line":"def tpool_execute(func: ty.Callable, *args, **kwargs):"},{"line_number":643,"context_line":"    \"\"\"Run func in a native thread\"\"\""},{"line_number":644,"context_line":"    return _pass_context(tpool.execute, func, *args, **kwargs)"},{"line_number":645,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"bb726a95_9983c6e7","line":642,"in_reply_to":"3bca9731_fac47dbc","updated":"2025-12-16 09:09:58.000000000","message":"yeah the return type here is the return type of the func passed in, not a future.","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"65d3a1f8c70273f035bd48e9d3e0717121551401","unresolved":false,"context_lines":[{"line_number":639,"context_line":"    return _pass_context(executor.submit, func, *args, **kwargs)"},{"line_number":640,"context_line":""},{"line_number":641,"context_line":""},{"line_number":642,"context_line":"def tpool_execute(func: ty.Callable, *args, **kwargs):"},{"line_number":643,"context_line":"    \"\"\"Run func in a native thread\"\"\""},{"line_number":644,"context_line":"    return _pass_context(tpool.execute, func, *args, **kwargs)"},{"line_number":645,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"6d54d235_33e7bc22","line":642,"in_reply_to":"bb726a95_9983c6e7","updated":"2025-12-16 15:12:54.000000000","message":"Acknowledged","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":1191,"context_line":"    return not monkey_patch.is_patched()"},{"line_number":1192,"context_line":""},{"line_number":1193,"context_line":""},{"line_number":1194,"context_line":"SCATTER_GATHER_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":1195,"context_line":""},{"line_number":1196,"context_line":""},{"line_number":1197,"context_line":"def get_scatter_gather_executor() -\u003e Executor:"}],"source_content_type":"text/x-python","patch_set":1,"id":"1a417991_9c7acc68","line":1194,"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\nSCATTER_GATHER_EXECUTOR: Executor | None \u003d None\n```","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":false,"context_lines":[{"line_number":1191,"context_line":"    return not monkey_patch.is_patched()"},{"line_number":1192,"context_line":""},{"line_number":1193,"context_line":""},{"line_number":1194,"context_line":"SCATTER_GATHER_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":1195,"context_line":""},{"line_number":1196,"context_line":""},{"line_number":1197,"context_line":"def get_scatter_gather_executor() -\u003e Executor:"}],"source_content_type":"text/x-python","patch_set":1,"id":"e23c6fed_3c09e1c0","line":1194,"in_reply_to":"1a417991_9c7acc68","updated":"2025-12-16 09:09:58.000000000","message":"Done","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":1232,"context_line":"    SCATTER_GATHER_EXECUTOR \u003d None"},{"line_number":1233,"context_line":""},{"line_number":1234,"context_line":""},{"line_number":1235,"context_line":"CACHE_IMAGES_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":1236,"context_line":""},{"line_number":1237,"context_line":""},{"line_number":1238,"context_line":"def get_cache_images_executor() -\u003e Executor:"}],"source_content_type":"text/x-python","patch_set":1,"id":"730c56a7_1ba56fc9","line":1235,"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\nCACHE_IMAGES_EXECUTOR: Executor | None \u003d None\n```","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":false,"context_lines":[{"line_number":1232,"context_line":"    SCATTER_GATHER_EXECUTOR \u003d None"},{"line_number":1233,"context_line":""},{"line_number":1234,"context_line":""},{"line_number":1235,"context_line":"CACHE_IMAGES_EXECUTOR: ty.Optional[Executor] \u003d None"},{"line_number":1236,"context_line":""},{"line_number":1237,"context_line":""},{"line_number":1238,"context_line":"def get_cache_images_executor() -\u003e Executor:"}],"source_content_type":"text/x-python","patch_set":1,"id":"550b2a3e_48e6a204","line":1235,"in_reply_to":"730c56a7_1ba56fc9","updated":"2025-12-16 09:09:58.000000000","message":"Done","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"1c17dabc704ee1909e4da1c65d6ce94837bad062","unresolved":true,"context_lines":[{"line_number":1269,"context_line":"    CACHE_IMAGES_EXECUTOR \u003d None"},{"line_number":1270,"context_line":""},{"line_number":1271,"context_line":""},{"line_number":1272,"context_line":"def _log_executor_stats(executor: Executor):"},{"line_number":1273,"context_line":"    if CONF.thread_pool_statistic_period \u003c 0:"},{"line_number":1274,"context_line":"        return"},{"line_number":1275,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"bc8aa076_20245371","line":1272,"updated":"2025-12-08 18:04:03.000000000","message":"```suggestion\ndef _log_executor_stats(executor: Executor) -\u003e None:\n```","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"43fdc8d1030589390c7c1e873ec18886cba04a32","unresolved":false,"context_lines":[{"line_number":1269,"context_line":"    CACHE_IMAGES_EXECUTOR \u003d None"},{"line_number":1270,"context_line":""},{"line_number":1271,"context_line":""},{"line_number":1272,"context_line":"def _log_executor_stats(executor: Executor):"},{"line_number":1273,"context_line":"    if CONF.thread_pool_statistic_period \u003c 0:"},{"line_number":1274,"context_line":"        return"},{"line_number":1275,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"398973bc_6c856c39","line":1272,"in_reply_to":"bc8aa076_20245371","updated":"2025-12-16 09:09:58.000000000","message":"Done","commit_id":"e5b46bad3ba0b2c2622ca8eed295a9c96aacf444"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"dde41ee168395d2291f23fc51a5ca95ff62471c4","unresolved":true,"context_lines":[{"line_number":83,"context_line":"# NOTE(gibi): futurist does not expose the common based class."},{"line_number":84,"context_line":"# NOTE(gibi): we can simplify this when eventlet is removed."},{"line_number":85,"context_line":"Executor: ty.TypeAlias \u003d ("},{"line_number":86,"context_line":"        futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor)"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":"DEFAULT_EXECUTOR: Executor | None \u003d None"},{"line_number":89,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7957252f_417173ee","line":86,"updated":"2026-01-19 10:55:42.000000000","message":"nit:\n\n```suggestion\n    futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor)\n```","commit_id":"627ab6c0d0cbddce059a9abda5e8cf6f033a1666"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"34e2780822568fb2824c44d6da8d0e9c4183df28","unresolved":false,"context_lines":[{"line_number":83,"context_line":"# NOTE(gibi): futurist does not expose the common based class."},{"line_number":84,"context_line":"# NOTE(gibi): we can simplify this when eventlet is removed."},{"line_number":85,"context_line":"Executor: ty.TypeAlias \u003d ("},{"line_number":86,"context_line":"        futurist.GreenThreadPoolExecutor | futurist.ThreadPoolExecutor)"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":"DEFAULT_EXECUTOR: Executor | None \u003d None"},{"line_number":89,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"28e7bdf4_e3cf6a34","line":86,"in_reply_to":"7957252f_417173ee","updated":"2026-01-29 10:57:36.000000000","message":"Done","commit_id":"627ab6c0d0cbddce059a9abda5e8cf6f033a1666"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":16,"context_line":"#    under the License."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"\"\"\"Utilities and helper functions.\"\"\""},{"line_number":19,"context_line":"import contextlib"},{"line_number":20,"context_line":"import datetime"},{"line_number":21,"context_line":"import functools"},{"line_number":22,"context_line":"import hashlib"}],"source_content_type":"text/x-python","patch_set":5,"id":"9f53b133_5eb16491","line":19,"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\nfrom collections.abc import Callable\nimport contextlib\n```\n\n`collections.abc.Callable` is subscriptable since 3.10 so `typing.Callable` is deprecated for removal.","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":568,"context_line":"        }"},{"line_number":569,"context_line":"    return trace_info"},{"line_number":570,"context_line":""},{"line_number":571,"context_line":""},{"line_number":572,"context_line":"def spawn("},{"line_number":573,"context_line":"    func: ty.Callable[..., ty.Any], *args: ty.Any, **kwargs: ty.Any"},{"line_number":574,"context_line":") -\u003e futurist.Future:"},{"line_number":575,"context_line":"    \"\"\"Passthrough method for eventlet.spawn."},{"line_number":576,"context_line":""},{"line_number":577,"context_line":"    This utility exists so that it can be stubbed for testing without"}],"source_content_type":"text/x-python","patch_set":5,"id":"ba3ce5b5_ea43c041","line":574,"range":{"start_line":571,"start_character":1,"end_line":574,"end_character":21},"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\n\nP \u003d ty.ParamSpec(\u0027P\u0027)\nR \u003d ty.TypeVar(\u0027R\u0027)\n\n\ndef spawn(\n    func: Callable[P, R], *args: P.args, **kwargs: P.kwargs,\n) -\u003e futurist.Future:\n```\n\nThis allows type checkers to ensure that the args and kwargs are valid for the `func` callable","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":585,"context_line":"    return spawn_on(_get_default_executor(), func, *args, **kwargs)"},{"line_number":586,"context_line":""},{"line_number":587,"context_line":""},{"line_number":588,"context_line":"def spawn_after("},{"line_number":589,"context_line":"    seconds: float,"},{"line_number":590,"context_line":"    func: ty.Callable[..., ty.Any],"},{"line_number":591,"context_line":"    *args: ty.Any, **kwargs: ty.Any"},{"line_number":592,"context_line":") -\u003e futurist.Future:"},{"line_number":593,"context_line":"    \"\"\"Executing the function asynchronously after the given time.\"\"\""},{"line_number":594,"context_line":""},{"line_number":595,"context_line":"    def delayed(*args, **kwargs):"}],"source_content_type":"text/x-python","patch_set":5,"id":"886126c8_ae37f67d","line":592,"range":{"start_line":588,"start_character":0,"end_line":592,"end_character":21},"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\ndef spawn_after(\n    seconds: float,\n    func: Callable[P, R],\n    *args: P.args,\n    **kwargs: P.kwargs,\n) -\u003e futurist.Future:\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":611,"context_line":"    return False"},{"line_number":612,"context_line":""},{"line_number":613,"context_line":""},{"line_number":614,"context_line":"def spawn_on("},{"line_number":615,"context_line":"    executor: Executor,"},{"line_number":616,"context_line":"    func: ty.Callable[..., ty.Any],"},{"line_number":617,"context_line":"    *args: ty.Any, **kwargs: ty.Any,"},{"line_number":618,"context_line":") -\u003e futurist.Future:"},{"line_number":619,"context_line":"    \"\"\"Passthrough method to run func on a thread in a given executor."},{"line_number":620,"context_line":""},{"line_number":621,"context_line":"    It will also grab the context from the threadlocal store and add it to"}],"source_content_type":"text/x-python","patch_set":5,"id":"b53285df_2b626b49","line":618,"range":{"start_line":614,"start_character":0,"end_line":618,"end_character":21},"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\ndef spawn_on(\n    executor: Executor,\n    func: Callable[P, R],\n    *args: P.args,\n    **kwargs: P.kwargs,\n) -\u003e futurist.Future:\n```\n\nYou get the idea 😄","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1044,"context_line":"    return norm_name"},{"line_number":1045,"context_line":""},{"line_number":1046,"context_line":""},{"line_number":1047,"context_line":"def raise_if_old_compute():"},{"line_number":1048,"context_line":"    # to avoid circular imports"},{"line_number":1049,"context_line":"    from nova import context as nova_context"},{"line_number":1050,"context_line":"    from nova.objects import service"}],"source_content_type":"text/x-python","patch_set":5,"id":"8e4b1b4f_bc45568f","line":1047,"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\ndef raise_if_old_compute() -\u003e None:\n```\n\nI didn\u0027t bother doing the rest of these.","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1104,"context_line":"    reset function. All exceptions raised by the wrapped function,"},{"line_number":1105,"context_line":"    logger and cleanup function will be propagated to the caller."},{"line_number":1106,"context_line":"    \"\"\""},{"line_number":1107,"context_line":"    def outer_wrapper(func):"},{"line_number":1108,"context_line":"        @ty.no_type_check"},{"line_number":1109,"context_line":"        @functools.wraps(func)"},{"line_number":1110,"context_line":"        def wrapper(*args, **kwargs):"},{"line_number":1111,"context_line":"            if not wrapper.called:"},{"line_number":1112,"context_line":"                # Note(sean-k-mooney): the called state is always"},{"line_number":1113,"context_line":"                # updated even if the wrapped function completes"}],"source_content_type":"text/x-python","patch_set":5,"id":"6e803347_961470af","line":1110,"range":{"start_line":1107,"start_character":0,"end_line":1110,"end_character":37},"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\n    def outer_wrapper(func: Callable[P, R]) -\u003e Callable[P, R]:\n        @functools.wraps(func)\n        def wrapper(*args: P.args, **kwargs: P.kwargs) -\u003e R:\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1121,"context_line":"            else:"},{"line_number":1122,"context_line":"                logger(message)"},{"line_number":1123,"context_line":""},{"line_number":1124,"context_line":"        wrapper.called \u003d False"},{"line_number":1125,"context_line":""},{"line_number":1126,"context_line":"        def reset(wrapper, *args, **kwargs):"},{"line_number":1127,"context_line":"            # Note(sean-k-mooney): we conditionally call the"}],"source_content_type":"text/x-python","patch_set":5,"id":"7d713d60_80053c53","line":1124,"updated":"2026-01-29 11:49:32.000000000","message":"This might not be necessary but I suspect mypy will insist on it.\n\n```suggestion\n        setattr(wrapper, \u0027called\u0027, False)\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1136,"context_line":"            finally:"},{"line_number":1137,"context_line":"                wrapper.called \u003d False"},{"line_number":1138,"context_line":""},{"line_number":1139,"context_line":"        wrapper.reset \u003d functools.partial(reset, wrapper)"},{"line_number":1140,"context_line":"        return wrapper"},{"line_number":1141,"context_line":"    return outer_wrapper"},{"line_number":1142,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"50b62b91_a4381c4a","line":1139,"updated":"2026-01-29 11:49:32.000000000","message":"as above\n\n```suggestion\n        setattr(wrapper, \u0027reset\u0027, functools.partial(reset, wrapper))\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1145,"context_line":"    \"\"\"This type exists to act as a placeholder and will never be raised\"\"\""},{"line_number":1146,"context_line":""},{"line_number":1147,"context_line":""},{"line_number":1148,"context_line":"def latch_error_on_raise(retryable\u003d(_SentinelException,)):"},{"line_number":1149,"context_line":"    \"\"\"This is a utility decorator to ensure if a function ever raises"},{"line_number":1150,"context_line":"    it will always raise the same exception going forward."},{"line_number":1151,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"f8c2577f_a1919109","line":1148,"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\ndef latch_error_on_raise(\n    retryable: tuple[type[BaseException], ...] \u003d (_SentinelException,),\n) -\u003e Callable[[Callable[P, R]], Callable[P, R]]:\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1153,"context_line":"    error as the db may be temporarily unavailable and we should allow"},{"line_number":1154,"context_line":"    mod_wsgi to retry"},{"line_number":1155,"context_line":"    \"\"\""},{"line_number":1156,"context_line":""},{"line_number":1157,"context_line":"    def outer_wrapper(func):"},{"line_number":1158,"context_line":"        @ty.no_type_check"},{"line_number":1159,"context_line":"        @functools.wraps(func)"},{"line_number":1160,"context_line":"        def wrapper(*args, **kwargs):"},{"line_number":1161,"context_line":"            if wrapper.error:"},{"line_number":1162,"context_line":"                raise wrapper.error"},{"line_number":1163,"context_line":"            try:"}],"source_content_type":"text/x-python","patch_set":5,"id":"12b29bb9_287240e8","line":1160,"range":{"start_line":1156,"start_character":1,"end_line":1160,"end_character":37},"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\n    def outer_wrapper(func: Callable[P, R]) -\u003e Callable[P, R]:\n        @functools.wraps(func)\n        def wrapper(*args: P.args, **kwargs: P.kwargs) -\u003e R:\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1282,"context_line":"                self.locks and all(lock.is_writer() for lock in self.locks))"},{"line_number":1283,"context_line":""},{"line_number":1284,"context_line":""},{"line_number":1285,"context_line":"def concurrency_mode_threading():"},{"line_number":1286,"context_line":"    \"\"\"Returns true if the service is running in threading mode, false if"},{"line_number":1287,"context_line":"    running in Eventlet mode"},{"line_number":1288,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":5,"id":"89a86812_53e0f135","line":1285,"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\ndef concurrency_mode_threading() -\u003e bool:\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1287,"context_line":"    running in Eventlet mode"},{"line_number":1288,"context_line":"    \"\"\""},{"line_number":1289,"context_line":"    from nova import monkey_patch"},{"line_number":1290,"context_line":"    return not monkey_patch.is_patched()"},{"line_number":1291,"context_line":""},{"line_number":1292,"context_line":""},{"line_number":1293,"context_line":"SCATTER_GATHER_EXECUTOR: Executor | None \u003d None"}],"source_content_type":"text/x-python","patch_set":5,"id":"3c96b5f8_7c55a225","line":1290,"updated":"2026-01-29 11:49:32.000000000","message":"you might need this until we type check that module\n\n\n\n```suggestion\n    return not monkey_patch.is_patched()  # type: ignore\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"828111637b33f478f4ec3f6c4caa5742e6b3b65e","unresolved":true,"context_lines":[{"line_number":1351,"context_line":"    return CACHE_IMAGES_EXECUTOR"},{"line_number":1352,"context_line":""},{"line_number":1353,"context_line":""},{"line_number":1354,"context_line":"def destroy_cache_images_executor():"},{"line_number":1355,"context_line":"    \"\"\"Closes the executor and resets the global to None to allow forked worker"},{"line_number":1356,"context_line":"    processes to properly init it."},{"line_number":1357,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":5,"id":"09d6a2ca_5a9ef141","line":1354,"updated":"2026-01-29 11:49:32.000000000","message":"```suggestion\ndef destroy_cache_images_executor() -\u003e None:\n```","commit_id":"9f74d1c5f2fb8ba060cb65b803afc5a89fe3888b"}]}
