Skip to content

Add Python 3.15 support - #146

Open
mbUSC wants to merge 3 commits into
singlestore-labs:mainfrom
mbUSC:python-3.15-support
Open

mbUSC wants to merge 3 commits into
singlestore-labs:mainfrom
mbUSC:python-3.15-support

Conversation

@mbUSC

@mbUSC mbUSC commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Python 3.15 removed zipimport.zipimporter.load_module(), which the external function server used to load a zipped environment file. It's now loaded with find_spec()/exec_module() instead. Those methods only exist from Python 3.10, so 3.9 keeps using load_module(); that branch can be removed when 3.9 support is dropped. If the module raises while importing, its sys.modules entry is removed before the error is re-raised, as load_module() did.

AwaitableUvicornServer now uses asyncio.get_running_loop() rather than get_event_loop(). Both callers already create it inside a running event loop, so behaviour is unchanged.

CI

  • Add 3.15 to the smoke-test and pre-commit matrices.
  • The smoke-test job also runs the new test_asgi_env_file on every Python version from 3.9 to 3.15. It loads a zip environment through main() with uvicorn mocked, and checks both a successful import and a failed one.

The cibuildwheel upgrade needed to build and test wheels on 3.15 is in a separate PR: #NNN.

Testing

Full suite run locally on 3.15.0 against SingleStore 9.1.1, with the management tests excluded:

3.15.0 3.14.5
Passed 967 967
Skipped 19 19
Failed 1 1

The one failure, TestServerProcessMode::test_process_mode_worker_handles_request, also fails on 3.14 on macOS and is unrelated to this change.

test_asgi_env_file passes on 3.9, 3.14 and 3.15. On main it fails on 3.15 with the load_module error, which confirms it catches the original bug.


Note

Medium Risk
Changes how zipped external-function environment files are imported—a deployment path—with version-specific branches, though behavior is covered by new tests.

Overview
Adds Python 3.15 to pre-commit and smoke-test CI matrices and removes the old note that 3.15 was intentionally excluded.

External function zip environment loading in asgi.main() no longer calls removed zipimporter.load_module() on 3.10+; it uses find_spec() / exec_module() instead, with 3.9 still on load_module(). Failed imports clear sys.modules like the old API.

AwaitableUvicornServer creates its startup future with asyncio.get_running_loop() instead of get_event_loop().

New test_asgi_env_file exercises zipped env import through main() (uvicorn mocked) and runs on every smoke-test Python version alongside test_basics.

Reviewed by Cursor Bugbot for commit ac40b8e. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The ZIP loader needs failed-import cache cleanup and regression coverage for the new compatibility path.

2 open issues
What changed in this PR

Adds Python 3.15 compatibility to the external-function server and extends CI coverage to the new interpreter.

Changes:

  • Replaces ZIP environment loading with find_spec()/exec_module(), retaining the Python 3.9 fallback.
  • Uses the running event loop to create the uvicorn startup future.
  • Adds Python 3.15 CI jobs and upgrades cibuildwheel, raising the Linux wheel requirement to glibc 2.28.
File Description
singlestoredb/​functions/​ext/​asgi.py Updates ZIP environment loading for Python 3.15.
singlestoredb/​apps/​_uvicorn_util.py Creates the startup future on the running loop.
.github/​workflows/​smoke-test.yml Adds Python 3.15 smoke coverage.
.github/​workflows/​publish.yml Upgrades cibuildwheel and selects Python 3.15 for wheel testing.
.github/​workflows/​pre-commit.yml Adds Python 3.15 to the matrix.

Review effort: Balanced

Comment thread singlestoredb/functions/ext/asgi.py Resolved
Comment thread singlestoredb/functions/ext/asgi.py Resolved

@kesmit13 kesmit13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see this split into two PRs. One for 3.15 support and a separate one for the update of cibuildwheel. The 3.15 changes seem straightforward, but we need to evaluate any side-effects of cibuildwheel updates more thoroughly.

@mbUSC
mbUSC requested a review from bharathts07 as a code owner October 23, 2026 08:05
@mbUSC

mbUSC commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Split out: the cibuildwheel upgrade is now #147.

The pre-commit checks failure is unrelated: ubuntu-latest moved to Ubuntu 26.04, which has no Python 3.9. #148 fixes it, and I'll update this branch from main once it merges.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are focused, preserve the supported compatibility paths, and include regression coverage with no unresolved blocking findings.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@kesmit13

Copy link
Copy Markdown
Collaborator

Can you rebase this? We've done some refactoring recently and there is an issue with resource cleanup in PRs. I pushed a fix for it so that the code checks should run cleanly now. Sorry for the inconvenience.

Your Name added 2 commits October 27, 2026 21:32
Python 3.15 removed zipimport.zipimporter.load_module(), which the
external function server used to load a zipped environment file. Load
it with find_spec()/exec_module() instead. Those methods only exist
from Python 3.10, so 3.9 keeps using load_module(); that branch can be
removed when 3.9 support is dropped.

Use asyncio.get_running_loop() in AwaitableUvicornServer rather than
get_event_loop(). Both callers already create it inside a running
event loop, so behaviour is unchanged.

Add 3.15 to the smoke-test and pre-commit matrices. The cibuildwheel
upgrade needed to build and test wheels on 3.15 is in singlestore-labs#147.

Tested locally on 3.15.0 against SingleStore 9.1.1 (management tests
excluded): 967 passed, 19 skipped, 1 failed, the same results as 3.14.
The failure, TestServerProcessMode::test_process_mode_worker_handles_request,
also fails on 3.14 on macOS and is unrelated to this change.
If the module in a zipped environment file raised while importing,
main() left the half-initialized module in sys.modules, and a later
import in the same process would return it without retrying. Remove
the entry and re-raise, as load_module() did.

Add test_asgi_env_file, which runs a zip environment through main()
with uvicorn mocked out and checks that its functions are found, and
that a failed import leaves nothing in sys.modules. The smoke-test job
runs it on every Python version, 3.9 through 3.15, since the loader
takes a different path on 3.9 than on 3.10+.
@mbUSC
mbUSC force-pushed the python-3.15-support branch from 281c47e to 6ccbc33 Compare October 28, 2026 04:51
@mbUSC

mbUSC commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

@kesmit13 No prob! Rebased onto main

This branch was successfully deployed

1 active (outdated) deployment
Base — 6ccbc33d Deployed Oct 28, 2026 by mbUSC via test-coverage #575
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants