UAT: asyncio.get_event_loop() used in 4 files — deprecated in Python 3.10+, raises DeprecationWarning and fails in Python 3.12+ when no running loop exists #3947

Open
opened 2026-04-06 07:42:40 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/concurrency/replace-get-event-loop-deprecation
  • Commit Message: fix(concurrency): replace deprecated asyncio.get_event_loop() with asyncio.get_running_loop()
  • Milestone: None — backlog
  • Parent Epic: TBD — needs manual linking

Backlog note: This issue was discovered during autonomous UAT operation
on milestone v3.2.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Background and Context

Code-level analysis of all Python files in src/cleveragents/ identified the use of asyncio.get_event_loop() in 4 files. This API is deprecated in Python 3.10+ and raises DeprecationWarning when called outside of a running event loop. In Python 3.12+, the warning is more prominent and the behavior change is imminent. The project targets Python 3.12+ (per pyproject.toml), making this an active compatibility risk.

Feature Area: Async and Concurrency Patterns — asyncio event loop management

Severity: Medium — asyncio.get_event_loop() is deprecated in Python 3.10+ and raises DeprecationWarning when called outside of a running event loop. In Python 3.12+, it raises DeprecationWarning and will eventually raise RuntimeError when no running loop exists.


Current Behavior

asyncio.get_event_loop() is used in 4 files:

1. src/cleveragents/agents/base.py (line 57):

def process_message_sync(self, message, context=None):
    return asyncio.get_event_loop().run_until_complete(
        self.process_message(message, context or {})
    )

This is a synchronous method that calls get_event_loop() and then run_until_complete(). In Python 3.12+, if called from a thread that has no running event loop, this raises DeprecationWarning. The correct pattern is asyncio.run(self.process_message(...)).

2. src/cleveragents/langgraph/nodes.py (lines 109, 274):

# Line 109 — inside async method execute():
loop = asyncio.get_event_loop()
start_time = loop.time()

# Line 274 — inside async method _execute_function():
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(None, lambda: fn(state))

Both are inside async def methods where asyncio.get_running_loop() should be used instead.

3. src/cleveragents/langgraph/bridge.py (line 227):

def create_future_task(msg):
    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(execute_graph(msg), loop=loop)

This is a sync callback called from an RxPY operator. The loop= parameter to ensure_future is also deprecated. The correct pattern is asyncio.get_running_loop().create_task(execute_graph(msg)).

4. src/cleveragents/reactive/route_bridge.py (line 89):

and (asyncio.get_event_loop().time() - last_updated) > idle_threshold

Inside an async def method — should use asyncio.get_running_loop().time().


Expected Behavior

All async code should use modern asyncio patterns compatible with Python 3.12+. The correct replacement for asyncio.get_event_loop() when inside an async context is asyncio.get_running_loop(). When outside an async context (e.g., in sync code that needs to run a coroutine), asyncio.run() should be used instead.


Python Version Impact

  • Python 3.10: DeprecationWarning emitted when get_event_loop() is called with no running loop
  • Python 3.12: DeprecationWarning is more prominent; behavior change imminent
  • Python 3.14 (planned): RuntimeError when called with no running loop

The project uses Python 3.12+ (per pyproject.toml), making this an active compatibility risk.


Acceptance Criteria

  • asyncio.get_event_loop() is replaced in all 4 affected files with the appropriate modern alternative
  • src/cleveragents/agents/base.py: process_message_sync uses asyncio.run() instead of get_event_loop().run_until_complete()
  • src/cleveragents/langgraph/nodes.py: both usages replaced with asyncio.get_running_loop()
  • src/cleveragents/langgraph/bridge.py: create_future_task uses asyncio.get_running_loop().create_task() and removes deprecated loop= parameter from ensure_future
  • src/cleveragents/reactive/route_bridge.py: usage replaced with asyncio.get_running_loop().time()
  • No DeprecationWarning is raised by any of these code paths under Python 3.12+
  • All existing tests continue to pass after the changes

Subtasks

  • Replace asyncio.get_event_loop().run_until_complete(...) in src/cleveragents/agents/base.py with asyncio.run(...)
  • Replace asyncio.get_event_loop() at line 109 in src/cleveragents/langgraph/nodes.py with asyncio.get_running_loop()
  • Replace asyncio.get_event_loop() at line 274 in src/cleveragents/langgraph/nodes.py with asyncio.get_running_loop()
  • Replace asyncio.get_event_loop() and deprecated loop= param in src/cleveragents/langgraph/bridge.py with asyncio.get_running_loop().create_task(...)
  • Replace asyncio.get_event_loop().time() in src/cleveragents/reactive/route_bridge.py with asyncio.get_running_loop().time()
  • Tests (Behave): Add/update BDD scenarios covering the affected async code paths
  • Tests (Robot): Add integration test verifying no DeprecationWarning is raised under Python 3.12+
  • Verify coverage >= 97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly (fix(concurrency): replace deprecated asyncio.get_event_loop() with asyncio.get_running_loop()), followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly (fix/concurrency/replace-get-event-loop-deprecation).
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
  • All nox stages pass.
  • Coverage >= 97%.

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/concurrency/replace-get-event-loop-deprecation` - **Commit Message**: `fix(concurrency): replace deprecated asyncio.get_event_loop() with asyncio.get_running_loop()` - **Milestone**: None — backlog - **Parent Epic**: TBD — needs manual linking > **Backlog note:** This issue was discovered during autonomous UAT operation > on milestone v3.2.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- ## Background and Context Code-level analysis of all Python files in `src/cleveragents/` identified the use of `asyncio.get_event_loop()` in 4 files. This API is deprecated in Python 3.10+ and raises `DeprecationWarning` when called outside of a running event loop. In Python 3.12+, the warning is more prominent and the behavior change is imminent. The project targets Python 3.12+ (per `pyproject.toml`), making this an active compatibility risk. **Feature Area:** Async and Concurrency Patterns — asyncio event loop management **Severity:** Medium — `asyncio.get_event_loop()` is deprecated in Python 3.10+ and raises `DeprecationWarning` when called outside of a running event loop. In Python 3.12+, it raises `DeprecationWarning` and will eventually raise `RuntimeError` when no running loop exists. --- ## Current Behavior `asyncio.get_event_loop()` is used in 4 files: **1. `src/cleveragents/agents/base.py` (line 57):** ```python def process_message_sync(self, message, context=None): return asyncio.get_event_loop().run_until_complete( self.process_message(message, context or {}) ) ``` This is a synchronous method that calls `get_event_loop()` and then `run_until_complete()`. In Python 3.12+, if called from a thread that has no running event loop, this raises `DeprecationWarning`. The correct pattern is `asyncio.run(self.process_message(...))`. **2. `src/cleveragents/langgraph/nodes.py` (lines 109, 274):** ```python # Line 109 — inside async method execute(): loop = asyncio.get_event_loop() start_time = loop.time() # Line 274 — inside async method _execute_function(): loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, lambda: fn(state)) ``` Both are inside `async def` methods where `asyncio.get_running_loop()` should be used instead. **3. `src/cleveragents/langgraph/bridge.py` (line 227):** ```python def create_future_task(msg): loop = asyncio.get_event_loop() task = asyncio.ensure_future(execute_graph(msg), loop=loop) ``` This is a sync callback called from an RxPY operator. The `loop=` parameter to `ensure_future` is also deprecated. The correct pattern is `asyncio.get_running_loop().create_task(execute_graph(msg))`. **4. `src/cleveragents/reactive/route_bridge.py` (line 89):** ```python and (asyncio.get_event_loop().time() - last_updated) > idle_threshold ``` Inside an `async def` method — should use `asyncio.get_running_loop().time()`. --- ## Expected Behavior All async code should use modern asyncio patterns compatible with Python 3.12+. The correct replacement for `asyncio.get_event_loop()` when inside an async context is `asyncio.get_running_loop()`. When outside an async context (e.g., in sync code that needs to run a coroutine), `asyncio.run()` should be used instead. --- ## Python Version Impact - Python 3.10: `DeprecationWarning` emitted when `get_event_loop()` is called with no running loop - Python 3.12: `DeprecationWarning` is more prominent; behavior change imminent - Python 3.14 (planned): `RuntimeError` when called with no running loop The project uses Python 3.12+ (per `pyproject.toml`), making this an active compatibility risk. --- ## Acceptance Criteria - [ ] `asyncio.get_event_loop()` is replaced in all 4 affected files with the appropriate modern alternative - [ ] `src/cleveragents/agents/base.py`: `process_message_sync` uses `asyncio.run()` instead of `get_event_loop().run_until_complete()` - [ ] `src/cleveragents/langgraph/nodes.py`: both usages replaced with `asyncio.get_running_loop()` - [ ] `src/cleveragents/langgraph/bridge.py`: `create_future_task` uses `asyncio.get_running_loop().create_task()` and removes deprecated `loop=` parameter from `ensure_future` - [ ] `src/cleveragents/reactive/route_bridge.py`: usage replaced with `asyncio.get_running_loop().time()` - [ ] No `DeprecationWarning` is raised by any of these code paths under Python 3.12+ - [ ] All existing tests continue to pass after the changes --- ## Subtasks - [ ] Replace `asyncio.get_event_loop().run_until_complete(...)` in `src/cleveragents/agents/base.py` with `asyncio.run(...)` - [ ] Replace `asyncio.get_event_loop()` at line 109 in `src/cleveragents/langgraph/nodes.py` with `asyncio.get_running_loop()` - [ ] Replace `asyncio.get_event_loop()` at line 274 in `src/cleveragents/langgraph/nodes.py` with `asyncio.get_running_loop()` - [ ] Replace `asyncio.get_event_loop()` and deprecated `loop=` param in `src/cleveragents/langgraph/bridge.py` with `asyncio.get_running_loop().create_task(...)` - [ ] Replace `asyncio.get_event_loop().time()` in `src/cleveragents/reactive/route_bridge.py` with `asyncio.get_running_loop().time()` - [ ] Tests (Behave): Add/update BDD scenarios covering the affected async code paths - [ ] Tests (Robot): Add integration test verifying no `DeprecationWarning` is raised under Python 3.12+ - [ ] Verify coverage >= 97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done - [ ] All subtasks above are completed and checked off. - [ ] A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly (`fix(concurrency): replace deprecated asyncio.get_event_loop() with asyncio.get_running_loop()`), followed by a blank line, then additional lines providing relevant details about the implementation. - [ ] The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly (`fix/concurrency/replace-get-event-loop-deprecation`). - [ ] The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. - [ ] All nox stages pass. - [ ] Coverage >= 97%. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
Author
Owner

⚠️ Orphan Issue — Needs Manual Linking

This issue was created without a known parent Epic. Per CONTRIBUTING.md, all non-Epic/non-Legendary issues must be linked to a parent Epic using Forgejo's dependency system (child blocks parent).

A maintainer should:

  1. Identify the appropriate parent Epic for asyncio/concurrency modernization work (or create one if none exists).
  2. Open this issue and add the parent Epic under "blocks" — so that this issue blocks the parent Epic.

This ensures the dependency graph is machine-readable and Forgejo can track completion correctly.


Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

⚠️ **Orphan Issue — Needs Manual Linking** This issue was created without a known parent Epic. Per CONTRIBUTING.md, all non-Epic/non-Legendary issues must be linked to a parent Epic using Forgejo's dependency system (child **blocks** parent). A maintainer should: 1. Identify the appropriate parent Epic for asyncio/concurrency modernization work (or create one if none exists). 2. Open this issue and add the parent Epic under **"blocks"** — so that this issue blocks the parent Epic. This ensures the dependency graph is machine-readable and Forgejo can track completion correctly. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#3947
No description provided.