mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix: Python 3.14 compatibility for OAuth device flow
Fixes weak reference error in asyncio.run() on Python 3.14.2. Python 3.14 introduced stricter event loop lifecycle management that causes weak reference errors when synchronous code (webbrowser.open) is called from within async contexts managed by asyncio.run(). Changes: - Run webbrowser.open() in ThreadPoolExecutor to isolate from event loop - Make display_user_instructions() async and await it in login flow - Adds Python 3.14 compatibility while maintaining backward compatibility Fixes #480 Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com> Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
This commit is contained in:
@@ -71,7 +71,7 @@ class CLIAuth:
|
||||
console.print(f"[red]Device authorization error: {e}[/red]")
|
||||
return None
|
||||
|
||||
def display_user_instructions(self, device_response: dict) -> None:
|
||||
async def display_user_instructions(self, device_response: dict) -> None:
|
||||
"""Display user instructions for device authorization."""
|
||||
user_code = device_response["user_code"]
|
||||
verification_uri = device_response["verification_uri"]
|
||||
@@ -87,9 +87,15 @@ class CLIAuth:
|
||||
console.print(f"[bold green]{verification_uri_complete}[/bold green]")
|
||||
|
||||
# Try to open browser automatically
|
||||
# Python 3.14: Run webbrowser.open in executor to avoid weak reference issues
|
||||
try:
|
||||
console.print("\n[dim]Opening browser automatically...[/dim]")
|
||||
webbrowser.open(verification_uri_complete)
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
await loop.run_in_executor(executor, webbrowser.open, verification_uri_complete)
|
||||
except Exception:
|
||||
pass # Silently fail if browser can't be opened
|
||||
|
||||
@@ -252,7 +258,7 @@ class CLIAuth:
|
||||
return False
|
||||
|
||||
# Step 2: Display user instructions
|
||||
self.display_user_instructions(device_response)
|
||||
await self.display_user_instructions(device_response)
|
||||
|
||||
# Step 3: Poll for token
|
||||
device_code = device_response["device_code"]
|
||||
|
||||
Reference in New Issue
Block a user