We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
import is broken
### Observed behavior

trying to import doesn't work:

![import](https://user-images.githubusercontent.com/2367265/69167242-a0724d00-0ac2-11ea-9a37-a21040f7f812.gif)


### Expected behavior

import should work

### User-facing consequences

cannot import

### Errors and logs

none observed

### Steps to reproduce

unsure. it happened during all imports, but then I cleared my `KOLIBRI_HOME` folder and things started working again

### Context

0.13.0 alpha 3


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kolibri/core/utils/cache.py`
Content:
```
1 from django.core.cache import caches
2 
3 from kolibri.utils.conf import OPTIONS
4 
5 
6 cache_options = OPTIONS["Cache"]
7 
8 
9 class CrossProcessCache(object):
10     def __init__(self, default_timeout=cache_options["CACHE_TIMEOUT"]):
11         self.default_timeout = default_timeout
12 
13     def __contains__(self, key):
14         if key in caches["default"]:
15             return True
16         if cache_options["CACHE_BACKEND"] != "redis" and key in caches["process_cache"]:
17             return True
18         return False
19 
20     def get(self, key, default=None, version=None):
21         if key in caches["default"] or cache_options["CACHE_BACKEND"] == "redis":
22             return caches["default"].get(key, default=default, version=version)
23         item = caches["process_cache"].get(key, default=None, version=None)
24         caches["default"].set(key, item, timeout=self.default_timeout, version=version)
25         return item
26 
27     def set(self, key, value, timeout=None, version=None):
28         caches["default"].set(
29             key, value, timeout=timeout or self.default_timeout, version=version
30         )
31         if cache_options["CACHE_BACKEND"] != "redis":
32             caches["process_cache"].set(
33                 key, value, timeout=timeout or self.default_timeout, version=version
34             )
35
```

Path: `kolibri/core/content/utils/import_export_content.py`
Content:
```
1 import hashlib
2 
3 from django.db.models import Sum
4 from requests.exceptions import ChunkedEncodingError
5 from requests.exceptions import ConnectionError
6 from requests.exceptions import HTTPError
7 from requests.exceptions import Timeout
8 
9 from kolibri.core.content.models import ContentNode
10 from kolibri.core.content.models import LocalFile
11 from kolibri.core.content.utils.content_types_tools import (
12     renderable_contentnodes_q_filter,
13 )
14 from kolibri.core.content.utils.importability_annotation import (
15     get_channel_stats_from_disk,
16 )
17 from kolibri.core.content.utils.importability_annotation import (
18     get_channel_stats_from_peer,
19 )
20 
21 try:
22     import OpenSSL
23 
24     SSLERROR = OpenSSL.SSL.Error
25 except ImportError:
26     import requests
27 
28     SSLERROR = requests.exceptions.SSLError
29 
30 RETRY_STATUS_CODE = [502, 503, 504, 521, 522, 523, 524]
31 
32 
33 def get_nodes_to_transfer(
34     channel_id,
35     node_ids,
36     exclude_node_ids,
37     available,
38     renderable_only=True,
39     drive_id=None,
40     peer_id=None,
41 ):
42     nodes_to_include = ContentNode.objects.filter(channel_id=channel_id)
43 
44     # if requested, filter down to only include particular topics/nodes
45     if node_ids:
46         nodes_to_include = nodes_to_include.filter(pk__in=node_ids).get_descendants(
47             include_self=True
48         )
49 
50     # if requested, filter out nodes we're not able to render
51     if renderable_only:
52         nodes_to_include = nodes_to_include.filter(renderable_contentnodes_q_filter)
53 
54     # filter down the query to remove files associated with nodes we've specifically been asked to exclude
55     if exclude_node_ids:
56         nodes_to_exclude = ContentNode.objects.filter(
57             pk__in=exclude_node_ids
58         ).get_descendants(include_self=True)
59 
60         nodes_to_include = nodes_to_include.order_by().difference(
61             nodes_to_exclude.order_by()
62         )
63 
64     # By default don't filter node ids by their underlying file importability
65     file_based_node_id_list = None
66     if drive_id:
67         file_based_node_id_list = get_channel_stats_from_disk(
68             channel_id, drive_id
69         ).keys()
70 
71     if peer_id:
72         file_based_node_id_list = get_channel_stats_from_peer(
73             channel_id, peer_id
74         ).keys()
75     if file_based_node_id_list is not None:
76         nodes_to_include = nodes_to_include.filter(pk__in=file_based_node_id_list)
77     return nodes_to_include.filter(available=available).order_by()
78 
79 
80 def get_files_to_transfer(
81     channel_id,
82     node_ids,
83     exclude_node_ids,
84     available,
85     renderable_only=True,
86     drive_id=None,
87     peer_id=None,
88 ):
89 
90     nodes_to_include = get_nodes_to_transfer(
91         channel_id,
92         node_ids,
93         exclude_node_ids,
94         renderable_only,
95         available,
96         drive_id=drive_id,
97         peer_id=peer_id,
98     )
99     return calculate_files_to_transfer(nodes_to_include, available)
100 
101 
102 def calculate_files_to_transfer(nodes_to_include, available):
103     files_to_transfer = LocalFile.objects.filter(
104         available=available, files__contentnode__in=nodes_to_include
105     )
106 
107     # Make sure the files are unique, to avoid duplicating downloads
108     files_to_transfer = files_to_transfer.distinct()
109 
110     # calculate the total file sizes across all files being returned in the queryset
111     total_bytes_to_transfer = (
112         files_to_transfer.aggregate(Sum("file_size"))["file_size__sum"] or 0
113     )
114 
115     return files_to_transfer, total_bytes_to_transfer
116 
117 
118 def _get_node_ids(node_ids):
119 
120     return (
121         ContentNode.objects.filter(pk__in=node_ids)
122         .get_descendants(include_self=True)
123         .values_list("id", flat=True)
124     )
125 
126 
127 def retry_import(e, **kwargs):
128     """
129     When an exception occurs during channel/content import, if
130         * there is an Internet connection error or timeout error,
131           or HTTPError where the error code is one of the RETRY_STATUS_CODE,
132           return return True to retry the file transfer
133         * the file does not exist on the server or disk, skip the file and return False.
134           This only applies to content import not channel import.
135         * otherwise, raise the  exception.
136     return value:
137         * True - needs retry.
138         * False - file is skipped. Does not need retry.
139     """
140 
141     skip_404 = kwargs.pop("skip_404")
142 
143     if (
144         isinstance(e, ConnectionError)
145         or isinstance(e, Timeout)
146         or isinstance(e, ChunkedEncodingError)
147         or (isinstance(e, HTTPError) and e.response.status_code in RETRY_STATUS_CODE)
148         or (isinstance(e, SSLERROR) and "decryption failed or bad record mac" in str(e))
149     ):
150         return True
151 
152     elif skip_404 and (
153         (isinstance(e, HTTPError) and e.response.status_code == 404)
154         or (isinstance(e, OSError) and e.errno == 2)
155     ):
156         return False
157 
158     else:
159         raise e
160 
161 
162 def compare_checksums(file_name, file_id):
163     hasher = hashlib.md5()
164     with open(file_name, "rb") as f:
165         # Read chunks of 4096 bytes for memory efficiency
166         for chunk in iter(lambda: f.read(4096), b""):
167             hasher.update(chunk)
168     checksum = hasher.hexdigest()
169     return checksum == file_id
170
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kolibri/core/content/utils/import_export_content.py b/kolibri/core/content/utils/import_export_content.py
--- a/kolibri/core/content/utils/import_export_content.py
+++ b/kolibri/core/content/utils/import_export_content.py
@@ -91,8 +91,8 @@
         channel_id,
         node_ids,
         exclude_node_ids,
-        renderable_only,
         available,
+        renderable_only=renderable_only,
         drive_id=drive_id,
         peer_id=peer_id,
     )
diff --git a/kolibri/core/utils/cache.py b/kolibri/core/utils/cache.py
--- a/kolibri/core/utils/cache.py
+++ b/kolibri/core/utils/cache.py
@@ -20,9 +20,13 @@
     def get(self, key, default=None, version=None):
         if key in caches["default"] or cache_options["CACHE_BACKEND"] == "redis":
             return caches["default"].get(key, default=default, version=version)
-        item = caches["process_cache"].get(key, default=None, version=None)
-        caches["default"].set(key, item, timeout=self.default_timeout, version=version)
-        return item
+        if key in caches["process_cache"]:
+            item = caches["process_cache"].get(key, default=None, version=None)
+            caches["default"].set(
+                key, item, timeout=self.default_timeout, version=version
+            )
+            return item
+        return default
 
     def set(self, key, value, timeout=None, version=None):
         caches["default"].set(

{"golden_diff": "diff --git a/kolibri/core/content/utils/import_export_content.py b/kolibri/core/content/utils/import_export_content.py\n--- a/kolibri/core/content/utils/import_export_content.py\n+++ b/kolibri/core/content/utils/import_export_content.py\n@@ -91,8 +91,8 @@\n         channel_id,\n         node_ids,\n         exclude_node_ids,\n-        renderable_only,\n         available,\n+        renderable_only=renderable_only,\n         drive_id=drive_id,\n         peer_id=peer_id,\n     )\ndiff --git a/kolibri/core/utils/cache.py b/kolibri/core/utils/cache.py\n--- a/kolibri/core/utils/cache.py\n+++ b/kolibri/core/utils/cache.py\n@@ -20,9 +20,13 @@\n     def get(self, key, default=None, version=None):\n         if key in caches[\"default\"] or cache_options[\"CACHE_BACKEND\"] == \"redis\":\n             return caches[\"default\"].get(key, default=default, version=version)\n-        item = caches[\"process_cache\"].get(key, default=None, version=None)\n-        caches[\"default\"].set(key, item, timeout=self.default_timeout, version=version)\n-        return item\n+        if key in caches[\"process_cache\"]:\n+            item = caches[\"process_cache\"].get(key, default=None, version=None)\n+            caches[\"default\"].set(\n+                key, item, timeout=self.default_timeout, version=version\n+            )\n+            return item\n+        return default\n \n     def set(self, key, value, timeout=None, version=None):\n         caches[\"default\"].set(\n", "issue": "import is broken\n### Observed behavior\r\n\r\ntrying to import doesn't work:\r\n\r\n![import](https://user-images.githubusercontent.com/2367265/69167242-a0724d00-0ac2-11ea-9a37-a21040f7f812.gif)\r\n\r\n\r\n### Expected behavior\r\n\r\nimport should work\r\n\r\n### User-facing consequences\r\n\r\ncannot import\r\n\r\n### Errors and logs\r\n\r\nnone observed\r\n\r\n### Steps to reproduce\r\n\r\nunsure. it happened during all imports, but then I cleared my `KOLIBRI_HOME` folder and things started working again\r\n\r\n### Context\r\n\r\n0.13.0 alpha 3\r\n\n", "before_files": [{"content": "from django.core.cache import caches\n\nfrom kolibri.utils.conf import OPTIONS\n\n\ncache_options = OPTIONS[\"Cache\"]\n\n\nclass CrossProcessCache(object):\n    def __init__(self, default_timeout=cache_options[\"CACHE_TIMEOUT\"]):\n        self.default_timeout = default_timeout\n\n    def __contains__(self, key):\n        if key in caches[\"default\"]:\n            return True\n        if cache_options[\"CACHE_BACKEND\"] != \"redis\" and key in caches[\"process_cache\"]:\n            return True\n        return False\n\n    def get(self, key, default=None, version=None):\n        if key in caches[\"default\"] or cache_options[\"CACHE_BACKEND\"] == \"redis\":\n            return caches[\"default\"].get(key, default=default, version=version)\n        item = caches[\"process_cache\"].get(key, default=None, version=None)\n        caches[\"default\"].set(key, item, timeout=self.default_timeout, version=version)\n        return item\n\n    def set(self, key, value, timeout=None, version=None):\n        caches[\"default\"].set(\n            key, value, timeout=timeout or self.default_timeout, version=version\n        )\n        if cache_options[\"CACHE_BACKEND\"] != \"redis\":\n            caches[\"process_cache\"].set(\n                key, value, timeout=timeout or self.default_timeout, version=version\n            )\n", "path": "kolibri/core/utils/cache.py"}, {"content": "import hashlib\n\nfrom django.db.models import Sum\nfrom requests.exceptions import ChunkedEncodingError\nfrom requests.exceptions import ConnectionError\nfrom requests.exceptions import HTTPError\nfrom requests.exceptions import Timeout\n\nfrom kolibri.core.content.models import ContentNode\nfrom kolibri.core.content.models import LocalFile\nfrom kolibri.core.content.utils.content_types_tools import (\n    renderable_contentnodes_q_filter,\n)\nfrom kolibri.core.content.utils.importability_annotation import (\n    get_channel_stats_from_disk,\n)\nfrom kolibri.core.content.utils.importability_annotation import (\n    get_channel_stats_from_peer,\n)\n\ntry:\n    import OpenSSL\n\n    SSLERROR = OpenSSL.SSL.Error\nexcept ImportError:\n    import requests\n\n    SSLERROR = requests.exceptions.SSLError\n\nRETRY_STATUS_CODE = [502, 503, 504, 521, 522, 523, 524]\n\n\ndef get_nodes_to_transfer(\n    channel_id,\n    node_ids,\n    exclude_node_ids,\n    available,\n    renderable_only=True,\n    drive_id=None,\n    peer_id=None,\n):\n    nodes_to_include = ContentNode.objects.filter(channel_id=channel_id)\n\n    # if requested, filter down to only include particular topics/nodes\n    if node_ids:\n        nodes_to_include = nodes_to_include.filter(pk__in=node_ids).get_descendants(\n            include_self=True\n        )\n\n    # if requested, filter out nodes we're not able to render\n    if renderable_only:\n        nodes_to_include = nodes_to_include.filter(renderable_contentnodes_q_filter)\n\n    # filter down the query to remove files associated with nodes we've specifically been asked to exclude\n    if exclude_node_ids:\n        nodes_to_exclude = ContentNode.objects.filter(\n            pk__in=exclude_node_ids\n        ).get_descendants(include_self=True)\n\n        nodes_to_include = nodes_to_include.order_by().difference(\n            nodes_to_exclude.order_by()\n        )\n\n    # By default don't filter node ids by their underlying file importability\n    file_based_node_id_list = None\n    if drive_id:\n        file_based_node_id_list = get_channel_stats_from_disk(\n            channel_id, drive_id\n        ).keys()\n\n    if peer_id:\n        file_based_node_id_list = get_channel_stats_from_peer(\n            channel_id, peer_id\n        ).keys()\n    if file_based_node_id_list is not None:\n        nodes_to_include = nodes_to_include.filter(pk__in=file_based_node_id_list)\n    return nodes_to_include.filter(available=available).order_by()\n\n\ndef get_files_to_transfer(\n    channel_id,\n    node_ids,\n    exclude_node_ids,\n    available,\n    renderable_only=True,\n    drive_id=None,\n    peer_id=None,\n):\n\n    nodes_to_include = get_nodes_to_transfer(\n        channel_id,\n        node_ids,\n        exclude_node_ids,\n        renderable_only,\n        available,\n        drive_id=drive_id,\n        peer_id=peer_id,\n    )\n    return calculate_files_to_transfer(nodes_to_include, available)\n\n\ndef calculate_files_to_transfer(nodes_to_include, available):\n    files_to_transfer = LocalFile.objects.filter(\n        available=available, files__contentnode__in=nodes_to_include\n    )\n\n    # Make sure the files are unique, to avoid duplicating downloads\n    files_to_transfer = files_to_transfer.distinct()\n\n    # calculate the total file sizes across all files being returned in the queryset\n    total_bytes_to_transfer = (\n        files_to_transfer.aggregate(Sum(\"file_size\"))[\"file_size__sum\"] or 0\n    )\n\n    return files_to_transfer, total_bytes_to_transfer\n\n\ndef _get_node_ids(node_ids):\n\n    return (\n        ContentNode.objects.filter(pk__in=node_ids)\n        .get_descendants(include_self=True)\n        .values_list(\"id\", flat=True)\n    )\n\n\ndef retry_import(e, **kwargs):\n    \"\"\"\n    When an exception occurs during channel/content import, if\n        * there is an Internet connection error or timeout error,\n          or HTTPError where the error code is one of the RETRY_STATUS_CODE,\n          return return True to retry the file transfer\n        * the file does not exist on the server or disk, skip the file and return False.\n          This only applies to content import not channel import.\n        * otherwise, raise the  exception.\n    return value:\n        * True - needs retry.\n        * False - file is skipped. Does not need retry.\n    \"\"\"\n\n    skip_404 = kwargs.pop(\"skip_404\")\n\n    if (\n        isinstance(e, ConnectionError)\n        or isinstance(e, Timeout)\n        or isinstance(e, ChunkedEncodingError)\n        or (isinstance(e, HTTPError) and e.response.status_code in RETRY_STATUS_CODE)\n        or (isinstance(e, SSLERROR) and \"decryption failed or bad record mac\" in str(e))\n    ):\n        return True\n\n    elif skip_404 and (\n        (isinstance(e, HTTPError) and e.response.status_code == 404)\n        or (isinstance(e, OSError) and e.errno == 2)\n    ):\n        return False\n\n    else:\n        raise e\n\n\ndef compare_checksums(file_name, file_id):\n    hasher = hashlib.md5()\n    with open(file_name, \"rb\") as f:\n        # Read chunks of 4096 bytes for memory efficiency\n        for chunk in iter(lambda: f.read(4096), b\"\"):\n            hasher.update(chunk)\n    checksum = hasher.hexdigest()\n    return checksum == file_id\n", "path": "kolibri/core/content/utils/import_export_content.py"}], "after_files": [{"content": "from django.core.cache import caches\n\nfrom kolibri.utils.conf import OPTIONS\n\n\ncache_options = OPTIONS[\"Cache\"]\n\n\nclass CrossProcessCache(object):\n    def __init__(self, default_timeout=cache_options[\"CACHE_TIMEOUT\"]):\n        self.default_timeout = default_timeout\n\n    def __contains__(self, key):\n        if key in caches[\"default\"]:\n            return True\n        if cache_options[\"CACHE_BACKEND\"] != \"redis\" and key in caches[\"process_cache\"]:\n            return True\n        return False\n\n    def get(self, key, default=None, version=None):\n        if key in caches[\"default\"] or cache_options[\"CACHE_BACKEND\"] == \"redis\":\n            return caches[\"default\"].get(key, default=default, version=version)\n        if key in caches[\"process_cache\"]:\n            item = caches[\"process_cache\"].get(key, default=None, version=None)\n            caches[\"default\"].set(\n                key, item, timeout=self.default_timeout, version=version\n            )\n            return item\n        return default\n\n    def set(self, key, value, timeout=None, version=None):\n        caches[\"default\"].set(\n            key, value, timeout=timeout or self.default_timeout, version=version\n        )\n        if cache_options[\"CACHE_BACKEND\"] != \"redis\":\n            caches[\"process_cache\"].set(\n                key, value, timeout=timeout or self.default_timeout, version=version\n            )\n", "path": "kolibri/core/utils/cache.py"}, {"content": "import hashlib\n\nfrom django.db.models import Sum\nfrom requests.exceptions import ChunkedEncodingError\nfrom requests.exceptions import ConnectionError\nfrom requests.exceptions import HTTPError\nfrom requests.exceptions import Timeout\n\nfrom kolibri.core.content.models import ContentNode\nfrom kolibri.core.content.models import LocalFile\nfrom kolibri.core.content.utils.content_types_tools import (\n    renderable_contentnodes_q_filter,\n)\nfrom kolibri.core.content.utils.importability_annotation import (\n    get_channel_stats_from_disk,\n)\nfrom kolibri.core.content.utils.importability_annotation import (\n    get_channel_stats_from_peer,\n)\n\ntry:\n    import OpenSSL\n\n    SSLERROR = OpenSSL.SSL.Error\nexcept ImportError:\n    import requests\n\n    SSLERROR = requests.exceptions.SSLError\n\nRETRY_STATUS_CODE = [502, 503, 504, 521, 522, 523, 524]\n\n\ndef get_nodes_to_transfer(\n    channel_id,\n    node_ids,\n    exclude_node_ids,\n    available,\n    renderable_only=True,\n    drive_id=None,\n    peer_id=None,\n):\n    nodes_to_include = ContentNode.objects.filter(channel_id=channel_id)\n\n    # if requested, filter down to only include particular topics/nodes\n    if node_ids:\n        nodes_to_include = nodes_to_include.filter(pk__in=node_ids).get_descendants(\n            include_self=True\n        )\n\n    # if requested, filter out nodes we're not able to render\n    if renderable_only:\n        nodes_to_include = nodes_to_include.filter(renderable_contentnodes_q_filter)\n\n    # filter down the query to remove files associated with nodes we've specifically been asked to exclude\n    if exclude_node_ids:\n        nodes_to_exclude = ContentNode.objects.filter(\n            pk__in=exclude_node_ids\n        ).get_descendants(include_self=True)\n\n        nodes_to_include = nodes_to_include.order_by().difference(\n            nodes_to_exclude.order_by()\n        )\n\n    # By default don't filter node ids by their underlying file importability\n    file_based_node_id_list = None\n    if drive_id:\n        file_based_node_id_list = get_channel_stats_from_disk(\n            channel_id, drive_id\n        ).keys()\n\n    if peer_id:\n        file_based_node_id_list = get_channel_stats_from_peer(\n            channel_id, peer_id\n        ).keys()\n    if file_based_node_id_list is not None:\n        nodes_to_include = nodes_to_include.filter(pk__in=file_based_node_id_list)\n    return nodes_to_include.filter(available=available).order_by()\n\n\ndef get_files_to_transfer(\n    channel_id,\n    node_ids,\n    exclude_node_ids,\n    available,\n    renderable_only=True,\n    drive_id=None,\n    peer_id=None,\n):\n\n    nodes_to_include = get_nodes_to_transfer(\n        channel_id,\n        node_ids,\n        exclude_node_ids,\n        available,\n        renderable_only=renderable_only,\n        drive_id=drive_id,\n        peer_id=peer_id,\n    )\n    return calculate_files_to_transfer(nodes_to_include, available)\n\n\ndef calculate_files_to_transfer(nodes_to_include, available):\n    files_to_transfer = LocalFile.objects.filter(\n        available=available, files__contentnode__in=nodes_to_include\n    )\n\n    # Make sure the files are unique, to avoid duplicating downloads\n    files_to_transfer = files_to_transfer.distinct()\n\n    # calculate the total file sizes across all files being returned in the queryset\n    total_bytes_to_transfer = (\n        files_to_transfer.aggregate(Sum(\"file_size\"))[\"file_size__sum\"] or 0\n    )\n\n    return files_to_transfer, total_bytes_to_transfer\n\n\ndef _get_node_ids(node_ids):\n\n    return (\n        ContentNode.objects.filter(pk__in=node_ids)\n        .get_descendants(include_self=True)\n        .values_list(\"id\", flat=True)\n    )\n\n\ndef retry_import(e, **kwargs):\n    \"\"\"\n    When an exception occurs during channel/content import, if\n        * there is an Internet connection error or timeout error,\n          or HTTPError where the error code is one of the RETRY_STATUS_CODE,\n          return return True to retry the file transfer\n        * the file does not exist on the server or disk, skip the file and return False.\n          This only applies to content import not channel import.\n        * otherwise, raise the  exception.\n    return value:\n        * True - needs retry.\n        * False - file is skipped. Does not need retry.\n    \"\"\"\n\n    skip_404 = kwargs.pop(\"skip_404\")\n\n    if (\n        isinstance(e, ConnectionError)\n        or isinstance(e, Timeout)\n        or isinstance(e, ChunkedEncodingError)\n        or (isinstance(e, HTTPError) and e.response.status_code in RETRY_STATUS_CODE)\n        or (isinstance(e, SSLERROR) and \"decryption failed or bad record mac\" in str(e))\n    ):\n        return True\n\n    elif skip_404 and (\n        (isinstance(e, HTTPError) and e.response.status_code == 404)\n        or (isinstance(e, OSError) and e.errno == 2)\n    ):\n        return False\n\n    else:\n        raise e\n\n\ndef compare_checksums(file_name, file_id):\n    hasher = hashlib.md5()\n    with open(file_name, \"rb\") as f:\n        # Read chunks of 4096 bytes for memory efficiency\n        for chunk in iter(lambda: f.read(4096), b\"\"):\n            hasher.update(chunk)\n    checksum = hasher.hexdigest()\n    return checksum == file_id\n", "path": "kolibri/core/content/utils/import_export_content.py"}]}