From 0e2d9ccd99e3789875cead32a1a59e7ef2a44599 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Tue, 4 Nov 2025 17:36:16 -0800 Subject: [PATCH] Backported Python 3.14 asyncio fix from dee0b942 Python 3.14 deprecated asyncio.get_event_loop() when there is no running event loop. This backports the run_sync() helper function and its usage from main branch to fix compatibility. Refs #2506 --- datasette/cli.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/datasette/cli.py b/datasette/cli.py index fd65ea94..76bcc9a9 100644 --- a/datasette/cli.py +++ b/datasette/cli.py @@ -50,6 +50,17 @@ except ImportError: pass +def run_sync(coro_func): + """Run an async callable to completion on a fresh event loop.""" + loop = asyncio.new_event_loop() + try: + asyncio.set_event_loop(loop) + return loop.run_until_complete(coro_func()) + finally: + asyncio.set_event_loop(None) + loop.close() + + class Config(click.ParamType): # This will be removed in Datasette 1.0 in favour of class Setting name = "config" @@ -182,8 +193,7 @@ def inspect(files, inspect_file, sqlite_extensions): operations against immutable database files. """ app = Datasette([], immutables=files, sqlite_extensions=sqlite_extensions) - loop = asyncio.get_event_loop() - inspect_data = loop.run_until_complete(inspect_(files, sqlite_extensions)) + inspect_data = run_sync(lambda: inspect_(files, sqlite_extensions)) if inspect_file == "-": sys.stdout.write(json.dumps(inspect_data, indent=2)) else: @@ -610,10 +620,10 @@ def serve( return ds # Run the "startup" plugin hooks - asyncio.get_event_loop().run_until_complete(ds.invoke_startup()) + run_sync(ds.invoke_startup) # Run async soundness checks - but only if we're not under pytest - asyncio.get_event_loop().run_until_complete(check_databases(ds)) + run_sync(lambda: check_databases(ds)) if get: client = TestClient(ds) @@ -633,9 +643,7 @@ def serve( if open_browser: if url is None: # Figure out most convenient URL - to table, database or homepage - path = asyncio.get_event_loop().run_until_complete( - initial_path_for_datasette(ds) - ) + path = run_sync(lambda: initial_path_for_datasette(ds)) url = f"http://{host}:{port}{path}" webbrowser.open(url) uvicorn_kwargs = dict(