Add Python 3.14 support#14395
Conversation
Build Artifacts
Smoke test screenshot |
rtibbles
left a comment
There was a problem hiding this comment.
Ready to be updated for full implementation. Not sure why there are so many commits here, so let's make this complete, and clean up the commit history for merge.
rtibbles
left a comment
There was a problem hiding this comment.
Oh, also please retarget and rebase this to release-v0.19.x - this was missing from the issue originally, apologies.
5158341 to
8f99de7
Compare
8f99de7 to
9602d26
Compare
9602d26 to
9e626a2
Compare
rtibbles
left a comment
There was a problem hiding this comment.
Looks like we need an additional monkey patch of pkg_utils find_loader method to make the WHL actually work?
rtibbles
left a comment
There was a problem hiding this comment.
These most recent changes are completely unrelated to the issue at hand. Feels like the wheels are coming off.
rtibbles
left a comment
There was a problem hiding this comment.
All tests pass - looking really good here!
Can you just do one last pass at cleaning up the commit history - but do not make any other changes, because you've got everything right now.
Python 3.14 changed super() objects to no longer support __dict__ attribute setting, breaking Django 3.2's BaseContext.__copy__. Add a monkey patch that uses object.__new__() with __dict__ copy instead. Also restore pkgutil.find_loader (removed in 3.14) which django-filter 21.1 calls at import time. Uses importlib.util.find_spec as the underlying implementation. Both patches follow the existing pattern of monkey_patch_distutils() and forward_port_cgi_module() in kolibri/utils/env.py.
Replace datetime.utcnow() with datetime.now(tz=timezone.utc) and datetime.utcfromtimestamp() with datetime.fromtimestamp(ts, tz=timezone.utc). These APIs are deprecated since Python 3.12 and emit DeprecationWarning. All replacements are backward-compatible to Python 3.6+.
- Add explicit ordering in content test to avoid dict ordering assumption that breaks on Python 3.14 - Use pytest 8+ on Python 3.14 to handle ast.Str removal - Skip pytest-pythonpath on Python 3.14+ and use pytest's built-in pythonpath configuration instead
- Update python_requires from <3.14 to <3.15 and add 3.14 classifier - Add Python 3.14 to tox, GitHub Actions matrices - Update le-utils to 0.2.15 and morango to 0.8.9 (both support 3.14) - Update docs to list 3.14 as supported
f0869fa to
cbf978f
Compare
|
Cleaned up the commit history. Consolidated 8 commits into 4 logical ones:
Also rebased onto latest |
rtibbles
left a comment
There was a problem hiding this comment.
Clean minimal implementation. Covers run time and test concerns without changing any runtime dependencies.
Summary
Add support for Python 3.14, which will ship as the default in Ubuntu 26.04 LTS (April 2026).
Runtime fix:
monkey_patch_base_context()inkolibri/utils/env.py— Django 3.2'sBaseContext.__copy__crashes on Python 3.14 becausesuper()objects no longer support__dict__attribute setting. The patch follows the existing pattern used for distutils and cgi monkey-patches. Can be removed when upgrading to Django 4.2+.Deprecation fixes:
datetime.utcnow()calls inkolibri/core/auth/api.py(uses existingnow()import),kolibri/plugins/facility/views.py(usesutc_now()fromtime_utils), andkolibri/core/tasks/test/taskrunner/test_scheduler.py(uses naivedatetime.now()).datetime.utcfromtimestamp()inkolibri/utils/version.pywith timezone-awarefromtimestamp(..., tz=utc).Test fix:
_recurse_and_assertin content tests — match nodes by ID instead of position, consistent with the sibling_assert_nodesmethod.Code review fixes:
process_user_downloads_for_removal()to prevent AttributeError when queryset is empty.ClassroomNotificationsViewset.list()except block to prevent NameError.MODELS_TO_DELETEfrom deprovision command, import fromkolibri.core.auth.utils.deprovisioninstead.reverse_path()call before while loop in_get_descendants_import_metadatasince the base URL is loop-invariant.bulk_createfor AttendanceRecord increate_attendance_for_classroomto avoid N individual.save()calls.Infrastructure:
setup.pyversion constraint from<3.14to<3.15and add classifier.References
Reviewer guidance
kolibri/utils/env.py:146-167— Themonkey_patch_base_context()is the most critical change. It replaces Django 3.2'sBaseContext.__copy__with a version that avoidscopy(super()). Verify the replacement correctly preserves__dict__attributes (tested viaRequestContextcopy intest/test_env_compat.py).AI usage
This PR was implemented by Claude Code following a written implementation plan. The plan was reviewed and approved before execution. All changes were verified against existing tests and new tests were written for the monkey-patch.
@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?