|
3 | 3 | - provides utility wrappers to run asynchronous functions in a blocking environment.
|
4 | 4 | - vendor functions from ipython_genutils that should be retired at some point.
|
5 | 5 | """
|
6 |
| -import asyncio |
7 |
| -import atexit |
8 |
| -import inspect |
9 | 6 | import os
|
10 |
| -import threading |
11 |
| -from typing import Optional |
12 |
| - |
13 |
| - |
14 |
| -class _TaskRunner: |
15 |
| - """A task runner that runs an asyncio event loop on a background thread.""" |
16 |
| - |
17 |
| - def __init__(self): |
18 |
| - self.__io_loop: Optional[asyncio.AbstractEventLoop] = None |
19 |
| - self.__runner_thread: Optional[threading.Thread] = None |
20 |
| - self.__lock = threading.Lock() |
21 |
| - atexit.register(self._close) |
22 |
| - |
23 |
| - def _close(self): |
24 |
| - if self.__io_loop: |
25 |
| - self.__io_loop.stop() |
26 |
| - |
27 |
| - def _runner(self): |
28 |
| - loop = self.__io_loop |
29 |
| - assert loop is not None |
30 |
| - try: |
31 |
| - loop.run_forever() |
32 |
| - finally: |
33 |
| - loop.close() |
34 |
| - |
35 |
| - def run(self, coro): |
36 |
| - """Synchronously run a coroutine on a background thread.""" |
37 |
| - with self.__lock: |
38 |
| - name = f"{threading.current_thread().name} - runner" |
39 |
| - if self.__io_loop is None: |
40 |
| - self.__io_loop = asyncio.new_event_loop() |
41 |
| - self.__runner_thread = threading.Thread(target=self._runner, daemon=True, name=name) |
42 |
| - self.__runner_thread.start() |
43 |
| - fut = asyncio.run_coroutine_threadsafe(coro, self.__io_loop) |
44 |
| - return fut.result(None) |
45 |
| - |
46 |
| - |
47 |
| -_runner_map = {} |
48 |
| -_loop_map = {} |
49 |
| - |
50 |
| - |
51 |
| -def run_sync(coro): |
52 |
| - def wrapped(*args, **kwargs): |
53 |
| - name = threading.current_thread().name |
54 |
| - inner = coro(*args, **kwargs) |
55 |
| - try: |
56 |
| - # If a loop is currently running in this thread, |
57 |
| - # use a task runner. |
58 |
| - asyncio.get_running_loop() |
59 |
| - if name not in _runner_map: |
60 |
| - _runner_map[name] = _TaskRunner() |
61 |
| - return _runner_map[name].run(inner) |
62 |
| - except RuntimeError: |
63 |
| - pass |
64 |
| - |
65 |
| - # Run the loop for this thread. |
66 |
| - if name not in _loop_map: |
67 |
| - _loop_map[name] = asyncio.new_event_loop() |
68 |
| - loop = _loop_map[name] |
69 |
| - return loop.run_until_complete(inner) |
70 |
| - |
71 |
| - wrapped.__doc__ = coro.__doc__ |
72 |
| - return wrapped |
73 |
| - |
74 |
| - |
75 |
| -async def ensure_async(obj): |
76 |
| - """Ensure a returned object is asynchronous.L |
77 |
| -
|
78 |
| - NOTE: This should only be used on methods of external classes, |
79 |
| - not on a `self` method. |
80 |
| - """ |
81 |
| - if inspect.isawaitable(obj): |
82 |
| - return await obj |
83 |
| - return obj |
| 7 | + |
| 8 | +from jupyter_core.utils import ensure_async # noqa: F401 |
| 9 | +from jupyter_core.utils import run_sync # noqa: F401 |
84 | 10 |
|
85 | 11 |
|
86 | 12 | def _filefind(filename, path_dirs=None):
|
|
0 commit comments