fix(async): replace get_event_loop() with get_running_loop() — salvage of #21930#22450
Merged
Conversation
… 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.
Contributor
🔎 Lint report:
|
| 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Salvage of #21930 by @Zhekinmaksim — replaces 9 calls to deprecated
asyncio.get_event_loop()withasyncio.get_running_loop()across 4 files, all unconditionally insideasync defbodies. Follow-up to #21293 which fixed the same anti-pattern incli.py.Why a salvage
#21930 was 109 commits behind
main, and its diff against currentmaincarried two unintended stale-branch reverts beyond the +9/-9 the author actually wrote:encoding="utf-8"addition on_tail_lines(cbce5e93f"codebase: add encoding='utf-8' to all bare open() calls (PLW1514)")9de893e3b"feat(windows): close native-Windows install gaps") — both the try/except aroundpty_bridgeimport and the runtime_PTY_BRIDGE_AVAILABLEcheck that gives Windows users a clean error instead of anImportErrorForce-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
tools/browser_cdp_tool.py_cdp_call()deadline + remaining computations insideasync with websockets.connecthermes_cli/web_server.pyget_status,_start_device_code_flow,submit_oauth_code— async FastAPI endpoints offloading blocking work torun_in_executorenvironments/agent_loop.pyHermesAgentLoop.run()— tool dispatch inside async rollout loopenvironments/benchmarks/terminalbench_2/terminalbench2_env.pyrollout_and_score_eval()— test verification thread offloadI verified all 9 sites are unconditionally inside
async defbodies, so a running loop is guaranteed and notry/except RuntimeErrorfallback 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
Pure +9/-9, no stale reverts.
python3 -m py_compile— clean on all 4 filesruff check— cleantests/tools/test_browser_cdp_tool.py+tests/hermes_cli/test_web_server.py— 156/156 pass viascripts/run_tests.shrg "asyncio.get_event_loop\(\)"in non-test/non-docs code — zero remaining occurrences (matches PR fix(async): replace get_event_loop() with get_running_loop() in async contexts #21930's claim)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
--rebaseto preserve @Zhekinmaksim's authorship in the commit history.Closes #21930