Repository: learningequality/kolibri

Issue:
0.16.0 RC1 fails if Samba/Ansible/etc are installed (e.g. with python3-markdown) on the same OS
Confirmed on both Debian 12 and Ubuntu — here's an example on a Debian 12.5 VM where the [Kolibri 0.16.0 RC1 .deb](https://github.com/learningequality/kolibri/releases/download/v0.16.0-rc1/kolibri_0.16.0rc1-0ubuntu1_all.deb) was installed.

Logs below: Hopefully @rtibbles and @jredrejo can tell if a quick fix is possible or not!

```
root@deb12:~# /usr/bin/kolibri --version
kolibri, version 0.16.0rc1

root@deb12:~# cat /etc/debian_version
12.5

root@deb12:~# uname -a
Linux box 6.1.0-18-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64 GNU/Linux
```

```
root@deb12:~# apt list -a kolibri python3-markdown
Listing... Done
kolibri/now 0.16.0rc1-0ubuntu1 all [installed,local]
kolibri/jammy 0.15.12-0ubuntu3 all

python3-markdown/stable,now 3.4.1-2 all [installed,automatic]
```

```
root@deb12:~# systemctl status kolibri
× kolibri.service - Kolibri
     Loaded: loaded (/etc/systemd/system/kolibri.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Fri 2024-02-16 17:19:26 EST; 19min ago
    Process: 26446 ExecStart=/usr/bin/kolibri start (code=exited, status=1/FAILURE)
        CPU: 1.411s

Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/dist/rest_framework/serializers.py", line 30, in <module>
Feb 16 17:19:26 box kolibri[26446]:     from rest_framework.compat import Mapping, postgres_fields, unicode_to_repr
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/dist/rest_framework/compat.py", line 176, in <module>
Feb 16 17:19:26 box kolibri[26446]:     if markdown.version <= '2.2':
Feb 16 17:19:26 box kolibri[26446]:        ^^^^^^^^^^^^^^^^
Feb 16 17:19:26 box kolibri[26446]: AttributeError: module 'markdown' has no attribute 'version'
Feb 16 17:19:26 box systemd[1]: kolibri.service: Control process exited, code=exited, status=1/FAILURE
Feb 16 17:19:26 box systemd[1]: kolibri.service: Failed with result 'exit-code'.
Feb 16 17:19:26 box systemd[1]: Failed to start kolibri.service - Kolibri.
Feb 16 17:19:26 box systemd[1]: kolibri.service: Consumed 1.411s CPU time.
```

```
root@deb12:~# journalctl -u kolibri
Feb 16 17:19:19 box systemd[1]: Starting kolibri.service - LSB: kolibri daemon, an offline education platform...
Feb 16 17:19:19 box runuser[26031]: pam_unix(runuser:session): session opened for user kolibri(uid=999) by (uid=0)
Feb 16 17:19:19 box runuser[26031]: pam_unix(runuser:session): session closed for user kolibri
Feb 16 17:19:19 box systemd[1]: kolibri.service: Control process exited, code=exited, status=1/FAILURE
Feb 16 17:19:19 box systemd[1]: kolibri.service: Failed with result 'exit-code'.
Feb 16 17:19:19 box systemd[1]: Failed to start kolibri.service - LSB: kolibri daemon, an offline education platform.
Feb 16 17:19:20 box systemd[1]: Starting kolibri.service - LSB: kolibri daemon, an offline education platform...
Feb 16 17:19:20 box runuser[26158]: pam_unix(runuser:session): session opened for user kolibri(uid=999) by (uid=0)
Feb 16 17:19:20 box runuser[26158]: pam_unix(runuser:session): session closed for user kolibri
Feb 16 17:19:20 box systemd[1]: kolibri.service: Control process exited, code=exited, status=1/FAILURE
Feb 16 17:19:20 box systemd[1]: kolibri.service: Failed with result 'exit-code'.
Feb 16 17:19:20 box systemd[1]: Failed to start kolibri.service - LSB: kolibri daemon, an offline education platform.
Feb 16 17:19:24 box systemd[1]: Starting kolibri.service - Kolibri...
Feb 16 17:19:26 box kolibri[26446]: INFO     2024-02-16 17:19:26,217 Option DEBUG in section [Server] being overridden by environment variable KOLIBRI_DEBUG
Feb 16 17:19:26 box kolibri[26446]: INFO     2024-02-16 17:19:26,217 Option DEBUG_LOG_DATABASE in section [Server] being overridden by environment variable KOLIBRI_DEBUG_LOG_DATABASE
Feb 16 17:19:26 box kolibri[26446]: INFO     2024-02-16 17:19:26,217 Option HTTP_PORT in section [Deployment] being overridden by environment variable KOLIBRI_HTTP_PORT
Feb 16 17:19:26 box kolibri[26446]: INFO     2024-02-16 17:19:26,217 Option URL_PATH_PREFIX in section [Deployment] being overridden by environment variable KOLIBRI_URL_PATH_PREFIX
Feb 16 17:19:26 box kolibri[26446]: INFO     2024-02-16 17:19:26,219 Attempting to setup using pre-migrated databases
Feb 16 17:19:26 box kolibri[26446]: ERROR    2024-02-16 17:19:26,291 The job tables were not fully migrated. Tried to create them in the database and an error occurred: module 'markdown' has no attribute 'version'
Feb 16 17:19:26 box kolibri[26446]: Error: Traceback (most recent call last):
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/utils/cli.py", line 193, in invoke
Feb 16 17:19:26 box kolibri[26446]:     initialize(**get_initialize_params())
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/utils/main.py", line 287, in initialize
Feb 16 17:19:26 box kolibri[26446]:     ensure_job_tables_created()
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/utils/sanity_checks.py", line 123, in ensure_job_tables_created
Feb 16 17:19:26 box kolibri[26446]:     from kolibri.core.tasks.main import job_storage
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/core/tasks/main.py", line 5, in <module>
Feb 16 17:19:26 box kolibri[26446]:     from kolibri.core.tasks.storage import Storage
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/core/tasks/storage.py", line 27, in <module>
Feb 16 17:19:26 box kolibri[26446]:     from kolibri.core.tasks.job import Job
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/core/tasks/job.py", line 19, in <module>
Feb 16 17:19:26 box kolibri[26446]:     from kolibri.core.tasks.validation import validate_interval
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/core/tasks/validation.py", line 4, in <module>
Feb 16 17:19:26 box kolibri[26446]:     from rest_framework import serializers
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/dist/rest_framework/serializers.py", line 30, in <module>
Feb 16 17:19:26 box kolibri[26446]:     from rest_framework.compat import Mapping, postgres_fields, unicode_to_repr
Feb 16 17:19:26 box kolibri[26446]:   File "/usr/lib/python3/dist-packages/kolibri/dist/rest_framework/compat.py", line 176, in <module>
Feb 16 17:19:26 box kolibri[26446]:     if markdown.version <= '2.2':
Feb 16 17:19:26 box kolibri[26446]:        ^^^^^^^^^^^^^^^^
Feb 16 17:19:26 box kolibri[26446]: AttributeError: module 'markdown' has no attribute 'version'
Feb 16 17:19:26 box systemd[1]: kolibri.service: Control process exited, code=exited, status=1/FAILURE
Feb 16 17:19:26 box systemd[1]: kolibri.service: Failed with result 'exit-code'.
Feb 16 17:19:26 box systemd[1]: Failed to start kolibri.service - Kolibri.
Feb 16 17:19:26 box systemd[1]: kolibri.service: Consumed 1.411s CPU time.
```

Related:

- https://github.com/learningequality/kolibri-installer-debian/issues/131
- https://github.com/learningequality/kolibri-installer-debian/pull/132


Discussion:
This bug has been fixed in every version of Python markdown except version 3.0.0 - do you know why this particular package is being pinned to here?

https://github.com/Python-Markdown/markdown/commit/6323ba6c98cadc19c0a7eebe9b09279b738dc109
Digging deeper it seems that even for bullseye the latest version of this package should include the bug fix https://packages.debian.org/search?keywords=python3-markdown 
Huge thanks @rtibbles as you seem well on the way to solving (-:  All I know is these 2 fail with 0.16.0 RC 1...

- python3-markdown 3.4.1 on Debian 12
  ```
  root@box:~# apt list python3-markdown
  Listing... Done
  python3-markdown/stable,now 3.4.1-2 all [installed,automatic]
  ```
- python3-markdown 3.5.2 on Ubuntu 24.04 (latest pre-release!
  ```
  root@box:~# apt list python3-markdown
  Listing... Done
  python3-markdown/noble,now 3.5.2-1 all [installed,automatic]
  ```
Oh, I see from your traceback that 3.4.2 is the installed version? This is even more confusing. 
> traceback that 3.4.2 is the installed version?

Yeah.  (3.4.1 actually, on Debian 12 Bookworm)
The really annoying thing about this is that we don't use the markdown library at all in Kolibri, so that's why we don't bundle it!

If we can't find a way to handle this just by properly pinning dependencies, I have a last ditch workaround in mind. 
Very Awesome if markdown pollution can be removed entirely! 🙃
OK, yes I see what is happening. The version attribute was reintroduced in 3.0.1 then deprecated and then removed, so it is indeed absent in the latest versions.

I will implement a fix in Kolibri to handle this. 

Resolving patch:
diff --git a/kolibri/utils/env.py b/kolibri/utils/env.py
--- a/kolibri/utils/env.py
+++ b/kolibri/utils/env.py
@@ -103,6 +103,17 @@ def check_python_versions():
         warn(warning_text, DeprecationWarning)
 
 
+def monkey_patch_markdown():
+    """
+    Monkey patch markdown module into module cache to set to None.
+    This is to avoid a bug caused by newer versions of markdown that causes
+    a crash during the attempted optional import of markdown in DRF.
+    """
+    # TODO: rtibbles remove this once we upgrade to a newer version of Django REST Framework
+    # that doesn't have this issue.
+    sys.modules["markdown"] = None
+
+
 def set_env():
     """
     Sets the Kolibri environment for the CLI or other application worker
@@ -114,6 +125,8 @@ def set_env():
     """
     check_python_versions()
 
+    monkey_patch_markdown()
+
     from kolibri import dist as kolibri_dist  # noqa
 
     monkey_patch_collections()


Test patch: