Skip to content

fix(async): replace get_event_loop() with get_running_loop() — salvage of #21930#22450

Merged
kshitijk4poor merged 1 commit into
mainfrom
salvage/get-running-loop-21930
May 9, 2026
Merged

fix(async): replace get_event_loop() with get_running_loop() — salvage of #21930#22450
kshitijk4poor merged 1 commit into
mainfrom
salvage/get-running-loop-21930

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Summary

Salvage of #21930 by @Zhekinmaksim — replaces 9 calls to deprecated asyncio.get_event_loop() with asyncio.get_running_loop() across 4 files, all unconditionally inside async def bodies. Follow-up to #21293 which fixed the same anti-pattern in cli.py.

Why a salvage

#21930 was 109 commits behind main, and its diff against current main carried two unintended stale-branch reverts beyond the +9/-9 the author actually wrote:

  1. Reverted the encoding="utf-8" addition on _tail_lines (cbce5e93f "codebase: add encoding='utf-8' to all bare open() calls (PLW1514)")
  2. Reverted the entire Windows PTY bridge guard (9de893e3b "feat(windows): close native-Windows install gaps") — both the try/except around pty_bridge import and the runtime _PTY_BRIDGE_AVAILABLE check that gives Windows users a clean error instead of an ImportError

Force-merging #21930 as-is would have silently undone both fixes. This salvage applies only the 9 intended swaps onto fresh main, preserving @Zhekinmaksim's authorship via --author.

Sites

File Sites Function
tools/browser_cdp_tool.py 4 _cdp_call() deadline + remaining computations inside async with websockets.connect
hermes_cli/web_server.py 3 get_status, _start_device_code_flow, submit_oauth_code — async FastAPI endpoints offloading blocking work to run_in_executor
environments/agent_loop.py 1 HermesAgentLoop.run() — tool dispatch inside async rollout loop
environments/benchmarks/terminalbench_2/terminalbench2_env.py 1 rollout_and_score_eval() — test verification thread offload

I verified all 9 sites are unconditionally inside async def bodies, so a running loop is guaranteed and no try/except RuntimeError fallback is needed (unlike the cli.py case in #21293, which ran from a background thread). Inside a coroutine, both functions return the same loop — semantics are identical.

Verification

$ git diff origin/main..HEAD --stat
 environments/agent_loop.py                                    | 2 +-
 environments/benchmarks/terminalbench_2/terminalbench2_env.py | 2 +-
 hermes_cli/web_server.py                                      | 6 +++---
 tools/browser_cdp_tool.py                                     | 8 ++++----
 4 files changed, 9 insertions(+), 9 deletions(-)

Pure +9/-9, no stale reverts.

Credit

Original work by @Zhekinmaksim in #21930. Their commit is preserved here with original authorship via git -c user.email=zhekinmaksim@gmail.com -c user.name=Zhekinmaksim. Closing #21930 with credit and explaining the salvage rationale on merge.

Notes for reviewer

Depends on #22449 (chore(release): add Zhekinmaksim to AUTHOR_MAP) being merged first.

Merge with --rebase to preserve @Zhekinmaksim's authorship in the commit history.

Closes #21930

… contexts

Follow-up to PR #21293 (cli.py), which fixed the same anti-pattern.
`asyncio.get_event_loop()` is documented as effectively "always returns
the running loop when called from a coroutine" and emits
DeprecationWarning/RuntimeWarning in some interpreter configurations.
The Python docs explicitly recommend get_running_loop() inside coroutines.

Replaces the remaining 9 call sites that are unconditionally inside
async def bodies:

- tools/browser_cdp_tool.py — _cdp_call() (4 sites): deadline + remaining
  computations inside the async websockets.connect context manager.
- hermes_cli/web_server.py — get_status, _start_device_code_flow,
  submit_oauth_code (3 sites): all FastAPI async endpoints offloading
  blocking httpx / PKCE work to run_in_executor.
- environments/agent_loop.py — HermesAgentLoop (1 site): tool dispatch
  inside the async rollout loop.
- environments/benchmarks/terminalbench_2/terminalbench2_env.py —
  rollout_and_score_eval (1 site): test verification thread offload.

All 9 sites are unconditionally inside async def bodies, so a running
loop is guaranteed and no try/except RuntimeError fallback is needed
(unlike the cli.py case in #21293, which ran from a background thread).

Behavior is identical on supported Python versions; aligns the codebase
with the post-#21293 idiom and avoids future warnings as the deprecation
hardens.

Salvaged from PR #21930 by @Zhekinmaksim onto current main (the
original branch was 109 commits behind and carried unintended
stale-branch reverts of unrelated landed changes — _tail_lines
encoding=utf-8 and the Windows PTY bridge guard). Only the 9 swaps
from the PR's intended scope are applied here.
@kshitijk4poor kshitijk4poor merged commit 4a1840e into main May 9, 2026
5 checks passed
@kshitijk4poor kshitijk4poor deleted the salvage/get-running-loop-21930 branch May 9, 2026 09:34
@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: salvage/get-running-loop-21930 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 7876 on HEAD, 0 on base (🆕 +7876)

🆕 New issues (4171):

Rule Count
unresolved-import 1290
invalid-argument-type 950
unresolved-attribute 920
invalid-assignment 453
unsupported-operator 122
invalid-parameter-default 120
not-subscriptable 83
invalid-method-override 82
invalid-return-type 36
no-matching-overload 31
call-non-callable 29
unresolved-reference 18
invalid-type-form 14
unused-type-ignore-comment 10
not-iterable 4
+6 more rules
First entries
tests/gateway/test_teams.py:13: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tools/mcp_tool.py:201: [unresolved-import] unresolved-import: Cannot resolve imported module `mcp.client.sse`
gateway/platforms/sms.py:291: [unresolved-import] unresolved-import: Cannot resolve imported module `aiohttp`
tools/browser_camofox.py:228: [invalid-parameter-default] invalid-parameter-default: Default value of type `None` is not assignable to annotated parameter type `dict[Unknown, Unknown]`
tools/environments/base.py:271: [invalid-return-type] invalid-return-type: Return type does not match returned value: expected `int`, found `int | None`
environments/benchmarks/terminalbench_2/terminalbench2_env.py:58: [unresolved-import] unresolved-import: Cannot resolve imported module `atroposlib.envs.server_handling.server_manager`
tests/tools/test_file_ops_cwd_tracking.py:23: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
gateway/platforms/wecom_callback.py:131: [unresolved-attribute] unresolved-attribute: Attribute `TCPSite` is not defined on `None` in union `Unknown | None`
tests/gateway/test_whatsapp_connect.py:19: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
optional-skills/migration/openclaw-migration/scripts/openclaw_to_hermes.py:2264: [invalid-argument-type] invalid-argument-type: Argument to bound method `Migrator.record` is incorrect: Expected `Path | None`, found `Literal["archive/hooks-config.json"]`
tests/hermes_cli/test_config.py:657: [invalid-argument-type] invalid-argument-type: Method `__getitem__` of type `Overload[(i: SupportsIndex, /) -> Unknown, (s: slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None], /) -> list[Unknown]]` cannot be called with key of type `Literal["user_message_preview"]` on object of type `list[Unknown]`
tests/test_mini_swe_runner.py:54: [invalid-assignment] invalid-assignment: Object of type `MagicMock` is not assignable to attribute `_create_env` of type `def _create_env(self) -> Unknown`
gateway/run.py:9293: [invalid-argument-type] invalid-argument-type: Argument to function `unlink` is incorrect: Expected `str | bytes | PathLike[str] | PathLike[bytes]`, found `None | str | Any`
tests/gateway/test_tts_media_routing.py:81: [unresolved-attribute] unresolved-attribute: Object of type `bound method _MediaRoutingAdapter.send_document(chat_id: str, file_path: str, caption: str | None = None, file_name: str | None = None, reply_to: str | None = None, metadata: dict[str, Any] | None = None, **kwargs) -> CoroutineType[Any, Any, SendResult]` has no attribute `assert_awaited_once_with`
gateway/platforms/whatsapp.py:963: [invalid-method-override] invalid-method-override: Invalid override of method `send_image_file`: Definition is incompatible with `BasePlatformAdapter.send_image_file`
agent/codex_responses_adapter.py:656: [no-matching-overload] no-matching-overload: No overload of bound method `dict.get` matches arguments
tests/cron/test_codex_execution_paths.py:93: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `list[dict[str, Any]]`, found `Unknown | None`
tests/gateway/test_matrix_mention.py:33: [invalid-assignment] invalid-assignment: Object of type `AsyncMock` is not assignable to attribute `handle_message` of type `def handle_message(self, event: MessageEvent) -> CoroutineType[Any, Any, None]`
plugins/google_meet/cli.py:166: [unresolved-import] unresolved-import: Cannot resolve imported module `playwright`
tests/tools/test_web_providers.py:158: [invalid-argument-type] invalid-argument-type: Method `__getitem__` of type `Overload[(i: SupportsIndex, /) -> str, (s: slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None], /) -> list[str]]` cannot be called with key of type `Literal["backend"]` on object of type `list[str]`
tests/gateway/test_auto_continue.py:9: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/agent/test_insights.py:152: [invalid-argument-type] invalid-argument-type: Argument to function `_has_known_pricing` is incorrect: Expected `str`, found `None`
tests/run_agent/test_strict_api_validation.py:11: [no-matching-overload] no-matching-overload: No overload of bound method `MutableMapping.setdefault` matches arguments
tests/tools/test_delegate.py:1955: [invalid-argument-type] invalid-argument-type: Argument to function `delegate_task` is incorrect: Expected `int | None`, found `str | Unknown`
tests/tools/test_mcp_oauth.py:11: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
... and 4146 more

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants