
🙂 Looking for an issue? Welcome! This issue is open for contribution. If this is the first time you’re requesting an issue, please:
- Read Contributing guidelines carefully. Pay extra attention to Using generative AI. Pull requests and comments that don’t follow the guidelines won’t be answered.
- Confirm that you’ve read the guidelines in your comment.

Overview
This task removes simple Python 2.7 compatibility code including outdated import statements, deprecated file operations, and compatibility shims. This is a great first issue for new contributors!
Difficulty: Beginner-friendly
Risk: Very low
Estimated changes: ~25 instances across ~15 files
Tasks
1. Remove from __future__ import statements
File: kolibri/plugins/qti_viewer/kolibri_plugin.py
Current (lines 1-3):
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
Action: Delete all three lines. These imports were needed for Python 2.7 compatibility and are unnecessary in Python 3.
2. Replace io.open() with built-in open()
In Python 3, the built-in open() function is equivalent to io.open(). Replace all instances and remove unnecessary import io statements (unless io.BytesIO or io.StringIO is also used in the file).
Pattern to find:
import io
# ...
with io.open(file_path, mode="r", encoding="utf-8") as f:
...
Pattern to replace with:
with open(file_path, mode="r", encoding="utf-8") as f:
...
Files to update (18 instances):
build_tools/i18n/utils.py (lines 55, 91)
build_tools/i18n/fonts.py (lines 357, 420)
kolibri/utils/i18n.py (line 35)
kolibri/utils/pskolibri/common.py (lines 132, 141)
kolibri/core/webpack/hooks.py (line 179)
kolibri/core/content/utils/paths.py (line 296)
kolibri/core/deviceadmin/utils.py (lines 108, 143) - Also remove the comment "Setting encoding=utf-8: io.open() is Python 2 compatible"
kolibri/core/content/utils/stopwords.py (line 11)
kolibri/core/sqlite/utils.py (line 113)
kolibri/core/logger/management/commands/generateuserdata.py (line 114)
kolibri/core/auth/constants/facility_presets.py (line 8)
kolibri/core/content/management/commands/generate_schema.py (lines 140, 160)
kolibri/core/content/test/test_channel_import.py (lines 423, 539, 556)
kolibri/core/analytics/test/test_utils.py (line 82)
3. Fix __nonzero__ method
File: kolibri/core/utils/nothing.py (line 13)
Current:
def __nonzero__(self): # Python 2
return False
__bool__ = __nonzero__ # this is for python3
Replace with:
def __bool__(self):
return False
Explanation: In Python 2, truthiness was defined by __nonzero__. Python 3 uses __bool__. We can now remove the Python 2 method.
4. Remove urllib2 compatibility
File: docker/entrypoint.py (lines 18-22)
Current:
# py2+py3 compatible imports via http://python-future.org/compatible_idioms.html
try:
from urllib.request import Request, build_opener, HTTPRedirectHandler
except ImportError:
from urllib2 import Request, HTTPRedirectHandler, build_opener
Replace with:
from urllib.request import Request, build_opener, HTTPRedirectHandler
Explanation: urllib2 only exists in Python 2. In Python 3, the functionality is in urllib.request.
Acceptance Criteria
Testing
Run all tests:
Run relevant tests for specific modules:
For utils changes:
pytest kolibri/utils/tests/
For core module changes:
pytest kolibri/core/utils/tests/test_nothing.py
pytest kolibri/core/content/test/
pytest kolibri/core/deviceadmin/tests/
For build_tools changes, no specific tests exist - ensure overall test suite passes.
How to find tests: Tests for a module kolibri/path/to/module.py are typically located at kolibri/path/to/test/test_module.py or kolibri/path/to/tests/test_module.py.
Tips
- Make changes incrementally and run tests frequently
- You can test individual files:
pytest path/to/test_file.py
- Use search to find all instances:
grep -r "io.open" kolibri/
- Don't forget to remove associated Python 2.7 comments when you remove code
Questions?
Comment on this issue if you need help or clarification!
Disclosure
🤖 This issue was written by Claude Code, under supervision, review and final edits by @rtibbles 🤖
🙂 Looking for an issue? Welcome! This issue is open for contribution. If this is the first time you’re requesting an issue, please:
Overview
This task removes simple Python 2.7 compatibility code including outdated import statements, deprecated file operations, and compatibility shims. This is a great first issue for new contributors!
Difficulty: Beginner-friendly
Risk: Very low
Estimated changes: ~25 instances across ~15 files
Tasks
1. Remove
from __future__ importstatementsFile:
kolibri/plugins/qti_viewer/kolibri_plugin.pyCurrent (lines 1-3):
Action: Delete all three lines. These imports were needed for Python 2.7 compatibility and are unnecessary in Python 3.
2. Replace
io.open()with built-inopen()In Python 3, the built-in
open()function is equivalent toio.open(). Replace all instances and remove unnecessaryimport iostatements (unlessio.BytesIOorio.StringIOis also used in the file).Pattern to find:
Pattern to replace with:
Files to update (18 instances):
build_tools/i18n/utils.py(lines 55, 91)build_tools/i18n/fonts.py(lines 357, 420)kolibri/utils/i18n.py(line 35)kolibri/utils/pskolibri/common.py(lines 132, 141)kolibri/core/webpack/hooks.py(line 179)kolibri/core/content/utils/paths.py(line 296)kolibri/core/deviceadmin/utils.py(lines 108, 143) - Also remove the comment "Setting encoding=utf-8: io.open() is Python 2 compatible"kolibri/core/content/utils/stopwords.py(line 11)kolibri/core/sqlite/utils.py(line 113)kolibri/core/logger/management/commands/generateuserdata.py(line 114)kolibri/core/auth/constants/facility_presets.py(line 8)kolibri/core/content/management/commands/generate_schema.py(lines 140, 160)kolibri/core/content/test/test_channel_import.py(lines 423, 539, 556)kolibri/core/analytics/test/test_utils.py(line 82)3. Fix
__nonzero__methodFile:
kolibri/core/utils/nothing.py(line 13)Current:
Replace with:
Explanation: In Python 2, truthiness was defined by
__nonzero__. Python 3 uses__bool__. We can now remove the Python 2 method.4. Remove urllib2 compatibility
File:
docker/entrypoint.py(lines 18-22)Current:
Replace with:
Explanation: urllib2 only exists in Python 2. In Python 3, the functionality is in urllib.request.
Acceptance Criteria
from __future__ importstatements removedio.open()calls replaced with built-inopen()import iostatements removed (check ifio.BytesIOorio.StringIOis used first)__nonzero__method replaced with__bool__in nothing.pyTesting
Run all tests:
Run relevant tests for specific modules:
For utils changes:
For core module changes:
For build_tools changes, no specific tests exist - ensure overall test suite passes.
How to find tests: Tests for a module
kolibri/path/to/module.pyare typically located atkolibri/path/to/test/test_module.pyorkolibri/path/to/tests/test_module.py.Tips
pytest path/to/test_file.pygrep -r "io.open" kolibri/Questions?
Comment on this issue if you need help or clarification!
Disclosure
🤖 This issue was written by Claude Code, under supervision, review and final edits by @rtibbles 🤖