1818import threading
1919import uuid
2020import warnings
21- from asyncio import Task , create_task
21+ from asyncio import AbstractEventLoop , Task , create_task
2222from concurrent .futures import Future
2323from contextlib import (
2424 asynccontextmanager ,
150150if constants .DEBUG :
151151 warnings .simplefilter ("always" , ResourceWarning )
152152
153- # `asyncio.get_event_loop()` is deprecated since Python 3.10:
154- _ASYNCIO_GET_EVENT_LOOP_IS_DEPRECATED = sys .version_info >= (3 , 10 , 0 )
155-
156153ComposeResult = Iterable [Widget ]
157154RenderResult : TypeAlias = "RenderableType | Visual | SupportsVisual"
158155"""Result of Widget.render()"""
@@ -2059,7 +2056,6 @@ async def run_async(
20592056 from textual .pilot import Pilot
20602057
20612058 app = self
2062-
20632059 auto_pilot_task : Task | None = None
20642060
20652061 if auto_pilot is None and constants .PRESS :
@@ -2092,27 +2088,29 @@ async def run_auto_pilot(
20922088 run_auto_pilot (auto_pilot , pilot ), name = repr (pilot )
20932089 )
20942090
2095- try :
2096- app ._loop = asyncio .get_running_loop ()
2097- app ._thread_id = threading .get_ident ()
2098-
2099- await app ._process_messages (
2100- ready_callback = None if auto_pilot is None else app_ready ,
2101- headless = headless ,
2102- inline = inline ,
2103- inline_no_clear = inline_no_clear ,
2104- mouse = mouse ,
2105- terminal_size = size ,
2106- )
2107- finally :
2091+ app ._loop = asyncio .get_running_loop ()
2092+ app ._thread_id = threading .get_ident ()
2093+ with app ._context ():
21082094 try :
2109- if auto_pilot_task is not None :
2110- await auto_pilot_task
2095+ await app ._process_messages (
2096+ ready_callback = None if auto_pilot is None else app_ready ,
2097+ headless = headless ,
2098+ inline = inline ,
2099+ inline_no_clear = inline_no_clear ,
2100+ mouse = mouse ,
2101+ terminal_size = size ,
2102+ )
21112103 finally :
21122104 try :
2113- await asyncio .shield (app ._shutdown ())
2114- except asyncio .CancelledError :
2115- pass
2105+ if auto_pilot_task is not None :
2106+ await auto_pilot_task
2107+ finally :
2108+ try :
2109+ await asyncio .shield (app ._shutdown ())
2110+ except asyncio .CancelledError :
2111+ pass
2112+ app ._loop = None
2113+ app ._thread_id = 0
21162114
21172115 return app .return_value
21182116
@@ -2125,6 +2123,7 @@ def run(
21252123 mouse : bool = True ,
21262124 size : tuple [int , int ] | None = None ,
21272125 auto_pilot : AutopilotCallbackType | None = None ,
2126+ loop : AbstractEventLoop | None = None ,
21282127 ) -> ReturnType | None :
21292128 """Run the app.
21302129
@@ -2136,36 +2135,24 @@ def run(
21362135 size: Force terminal size to `(WIDTH, HEIGHT)`,
21372136 or None to auto-detect.
21382137 auto_pilot: An auto pilot coroutine.
2139-
2138+ loop: Asyncio loop instance, or `None` to use default.
21402139 Returns:
21412140 App return value.
21422141 """
21432142
21442143 async def run_app () -> None :
21452144 """Run the app."""
2146- self ._loop = asyncio .get_running_loop ()
2147- self ._thread_id = threading .get_ident ()
2148- with self ._context ():
2149- try :
2150- await self .run_async (
2151- headless = headless ,
2152- inline = inline ,
2153- inline_no_clear = inline_no_clear ,
2154- mouse = mouse ,
2155- size = size ,
2156- auto_pilot = auto_pilot ,
2157- )
2158- finally :
2159- self ._loop = None
2160- self ._thread_id = 0
2145+ await self .run_async (
2146+ headless = headless ,
2147+ inline = inline ,
2148+ inline_no_clear = inline_no_clear ,
2149+ mouse = mouse ,
2150+ size = size ,
2151+ auto_pilot = auto_pilot ,
2152+ )
21612153
2162- if _ASYNCIO_GET_EVENT_LOOP_IS_DEPRECATED :
2163- # N.B. This doesn't work with Python<3.10, as we end up with 2 event loops:
2164- asyncio .run (run_app ())
2165- else :
2166- # However, this works with Python<3.10:
2167- event_loop = asyncio .get_event_loop ()
2168- event_loop .run_until_complete (run_app ())
2154+ event_loop = asyncio .get_event_loop () if loop is None else loop
2155+ event_loop .run_until_complete (run_app ())
21692156 return self .return_value
21702157
21712158 async def _on_css_change (self ) -> None :
0 commit comments