66import threading
77import asyncio
88import inspect
9- from typing import Any , Callable , Coroutine , TypeVar , Awaitable
9+ import warnings
1010
11+ from typing import Any , Callable , Awaitable , TypeVar
1112
1213T = TypeVar ("T" )
1314
@@ -24,15 +25,42 @@ def event_loop(self) -> asyncio.AbstractEventLoop:
2425 """Get the event loop for the cocoindex library."""
2526 with self ._lock :
2627 if self ._event_loop is None :
27- self ._event_loop = asyncio .new_event_loop ()
28- threading .Thread (
29- target = self ._event_loop .run_forever , daemon = True
30- ).start ()
28+ loop = asyncio .new_event_loop ()
29+ self ._event_loop = loop
30+
31+ def _runner (l : asyncio .AbstractEventLoop ) -> None :
32+ asyncio .set_event_loop (l )
33+ l .run_forever ()
34+
35+ threading .Thread (target = _runner , args = (loop ,), daemon = True ).start ()
3136 return self ._event_loop
3237
33- def run (self , coro : Coroutine [ Any , Any , T ]) -> T :
38+ def run (self , coro ) :
3439 """Run a coroutine in the event loop, blocking until it finishes. Return its result."""
35- return asyncio .run_coroutine_threadsafe (coro , self .event_loop ).result ()
40+ try :
41+ running_loop = asyncio .get_running_loop ()
42+ except RuntimeError :
43+ running_loop = None
44+
45+ loop = self .event_loop
46+
47+ if running_loop is not None :
48+ if running_loop is loop :
49+ raise RuntimeError (
50+ "CocoIndex sync API was called from inside CocoIndex's async context. "
51+ "Use the async variant of this method instead."
52+ )
53+ warnings .warn (
54+ "CocoIndex sync API was called inside an existing event loop. "
55+ "This may block other tasks. Prefer the async method." ,
56+ RuntimeWarning ,
57+ stacklevel = 2 ,
58+ )
59+ fut = asyncio .run_coroutine_threadsafe (coro , loop )
60+ return fut .result ()
61+
62+ fut = asyncio .run_coroutine_threadsafe (coro , loop )
63+ return fut .result ()
3664
3765
3866execution_context = _ExecutionContext ()
0 commit comments