We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
"TypeError: u'<url>' is not JSON serializable" on upload to backends other than S3
File upload to "django" and "filesystem" backends is currently broken. Each attempt to generate an upload URL fails with the following error:

```
Traceback (most recent call last):                                                                                                                            
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 41, in inner                                                          
    response = get_response(request)                                                                                                                          
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 249, in _legacy_get_response                                               
    response = self._get_response(request)                                                                                                                    
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 187, in _get_response                                                      
    response = self.process_exception_by_middleware(e, request)                                                                                               
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 185, in _get_response                                                      
    response = wrapped_callback(request, *callback_args, **callback_kwargs)                                                                                   
  File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 185, in inner                                                                
    return func(*args, **kwargs)                                                                                                                              
  File "/openedx/edx-platform/lms/djangoapps/courseware/module_render.py", line 962, in handle_xblock_callback                                                
    return _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, course=course)                                                               
  File "/openedx/edx-platform/lms/djangoapps/courseware/module_render.py", line 1068, in _invoke_xblock_handler                                               
    resp = instance.handle(handler, req, suffix)                                                                                                              
  File "/usr/local/lib/python2.7/dist-packages/xblock/mixins.py", line 90, in handle                                                                          
    return self.runtime.handle(self, handler_name, request, suffix)                                                                                           
  File "/openedx/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 1347, in handle                                                                   
    return super(MetricsMixin, self).handle(block, handler_name, request, suffix=suffix)                                                                      
  File "/usr/local/lib/python2.7/dist-packages/xblock/runtime.py", line 1037, in handle                                                                       
    results = handler(request, suffix)                                                                                                                        
  File "/usr/local/lib/python2.7/dist-packages/xblock/mixins.py", line 74, in wrapper                                                                         
    response = json.dumps(response)                                                                                                                           
  File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps                                                                                              
    return _default_encoder.encode(obj)    
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: u'/openassessment/fileupload/django/4dd623a62f4e626d827277cd3fedaf45/course-v1:org+video1+01/block-v1:org+video1+01+type@openassessment+block@25d85
51f741342ac919590db2e72091b/' is not JSON serializable
```

This error is due to the fact that urls returned by 'django' and 'filesystem' backends are computed with `django.core.urlresolvers.reverse_lazy`. Thus, they are not unicode, but `django.utils.functional.__proxy__` objects. The TypeError is raised when calling `json.dumps()` on `{'success': True, 'url': url_object}` in `xblock.mixins.HandlersMixin.json_handler`.

I can easily solve the problem by replacing `reverse_lazy` by `reverse`. However, I wonder what was the original reason to use `reverse_lazy`? The change was introduced in commit 3e13d27df by @efischer19.

Python tests pass successfully if I replace `reverse_lazy` by `reverse`.

I believe both ORA2 backends are broken for the current Open edX Hawthorn release. 
 
(this error was first discovered [here](https://github.com/regisb/openedx-docker/issues/97))

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setup.py`
Content:
```
1 #!/usr/bin/env python
2 from setuptools import find_packages, setup
3 
4 
5 def is_requirement(line):
6     """
7     Return True if the requirement line is a package requirement;
8     that is, it is not blank, a comment, or editable.
9     """
10     # Remove whitespace at the start/end of the line
11     line = line.strip()
12 
13     # Skip blank lines, comments, and editable installs
14     return not (
15         line == '' or
16         line.startswith('-r') or
17         line.startswith('#') or
18         line.startswith('-e') or
19         line.startswith('git+')
20     )
21 
22 def load_requirements(*requirements_paths):
23     """
24     Load all requirements from the specified requirements files.
25     Returns a list of requirement strings.
26     """
27     requirements = set()
28     for path in requirements_paths:
29         requirements.update(
30             line.strip() for line in open(path).readlines()
31             if is_requirement(line)
32         )
33     return list(requirements)
34 
35 setup(
36     name='ora2',
37     version='2.2.1',
38     author='edX',
39     url='http://github.com/edx/edx-ora2',
40     description='edx-ora2',
41     license='AGPL',
42     classifiers=[
43         'Development Status :: 3 - Alpha',
44         'Framework :: Django :: 1.11',
45         'Intended Audience :: Developers',
46         'License :: OSI Approved :: GNU Affero General Public License v3',
47         'Operating System :: OS Independent',
48         'Programming Language :: Python',
49     ],
50     packages=find_packages(include=['openassessment*'], exclude=['*.test', '*.tests']),
51     include_package_data=True,
52     install_requires=load_requirements('requirements/base.txt', "requirements/django.txt"),
53     tests_require=load_requirements('requirements/test.txt'),
54     entry_points={
55         'xblock.v1': [
56             'openassessment = openassessment.xblock.openassessmentblock:OpenAssessmentBlock',
57         ]
58     },
59 )
60
```

Path: `openassessment/fileupload/backends/filesystem.py`
Content:
```
1 from django.conf import settings
2 import django.core.cache
3 from django.core.urlresolvers import reverse_lazy
4 from django.utils.encoding import smart_text
5 
6 from .. import exceptions
7 from .base import BaseBackend
8 
9 
10 class Backend(BaseBackend):
11     """
12     Upload openassessment student files to a local filesystem. Note
13     that in order to use this file storage backend, you need to include the
14     urls from openassessment.fileupload in your urls.py file:
15 
16     E.g:
17         url(r'^openassessment/storage', include(openassessment.fileupload.urls)),
18 
19     The ORA2_FILEUPLOAD_CACHE_NAME setting will also have to be defined for the
20     name of the django.core.cache instance which will maintain the list of
21     active storage URLs.
22 
23     E.g:
24 
25         ORA2_FILEUPLOAD_CACHE_NAME = "ora2-storage"
26         CACHES = {
27             ...
28             'ora2-storage': {
29                 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
30                 ...
31             },
32             ...
33         }
34     """
35 
36     def get_upload_url(self, key, content_type):
37         make_upload_url_available(self._get_key_name(key), self.UPLOAD_URL_TIMEOUT)
38         return self._get_url(key)
39 
40     def get_download_url(self, key):
41         make_download_url_available(self._get_key_name(key), self.DOWNLOAD_URL_TIMEOUT)
42         return self._get_url(key)
43 
44     def remove_file(self, key):
45         from openassessment.fileupload.views_filesystem import safe_remove, get_file_path
46         return safe_remove(get_file_path(self._get_key_name(key)))
47 
48     def _get_url(self, key):
49         key_name = self._get_key_name(key)
50         url = reverse_lazy("openassessment-filesystem-storage", kwargs={'key': key_name})
51         return url
52 
53 
54 def get_cache():
55     """
56     Returns a django.core.cache instance in charge of maintaining the
57     authorized upload and download URL.
58 
59     Raises:
60         FileUploadInternalError if the cache name setting is not defined.
61         InvalidCacheBackendError if the corresponding cache backend has not
62         been configured.
63     """
64     cache_name = getattr(settings, "ORA2_FILEUPLOAD_CACHE_NAME", None)
65     if cache_name is None:
66         raise exceptions.FileUploadInternalError("Undefined cache backend for file upload")
67     return django.core.cache.caches[cache_name]
68 
69 
70 def make_upload_url_available(url_key_name, timeout):
71     """
72     Authorize an upload URL.
73 
74     Arguments:
75         url_key_name (str): key that uniquely identifies the upload url
76         timeout (int): time in seconds before the url expires
77     """
78     get_cache().set(
79         smart_text(get_upload_cache_key(url_key_name)),
80         1, timeout
81     )
82 
83 
84 def make_download_url_available(url_key_name, timeout):
85     """
86     Authorize a download URL.
87 
88     Arguments:
89         url_key_name (str): key that uniquely identifies the url
90         timeout (int): time in seconds before the url expires
91     """
92     get_cache().set(
93         smart_text(get_download_cache_key(url_key_name)),
94         1, timeout
95     )
96 
97 
98 def is_upload_url_available(url_key_name):
99     """
100     Return True if the corresponding upload URL is available.
101     """
102     return get_cache().get(smart_text(get_upload_cache_key(url_key_name))) is not None
103 
104 
105 def is_download_url_available(url_key_name):
106     """
107     Return True if the corresponding download URL is available.
108     """
109     return get_cache().get(smart_text(get_download_cache_key(url_key_name))) is not None
110 
111 
112 def get_upload_cache_key(url_key_name):
113     return "upload/" + url_key_name
114 
115 
116 def get_download_cache_key(url_key_name):
117     return "download/" + url_key_name
118
```

Path: `openassessment/fileupload/backends/django_storage.py`
Content:
```
1 import os
2 
3 from django.core.files.base import ContentFile
4 from django.core.files.storage import default_storage
5 from django.core.urlresolvers import reverse_lazy
6 
7 from .base import BaseBackend
8 
9 
10 class Backend(BaseBackend):
11     """
12     Manage openassessment student files uploaded using the default django storage settings.
13     """
14     def get_upload_url(self, key, content_type):
15         """
16         Return the URL pointing to the ORA2 django storage upload endpoint.
17         """
18         return reverse_lazy("openassessment-django-storage", kwargs={'key': key})
19 
20     def get_download_url(self, key):
21         """
22         Return the django storage download URL for the given key.
23 
24         Returns None if no file exists at that location.
25         """
26         path = self._get_file_path(key)
27         if default_storage.exists(path):
28             return default_storage.url(path)
29         return None
30 
31     def upload_file(self, key, content):
32         """
33         Upload the given file content to the keyed location.
34         """
35         path = self._get_file_path(key)
36         saved_path = default_storage.save(path, ContentFile(content))
37         return saved_path
38 
39     def remove_file(self, key):
40         """
41         Remove the file at the given keyed location.
42 
43         Returns True if the file exists, and was removed.
44         Returns False if the file does not exist, and so was not removed.
45         """
46         path = self._get_file_path(key)
47         if default_storage.exists(path):
48             default_storage.delete(path)
49             return True
50         return False
51 
52     def _get_file_name(self, key):
53         """
54         Returns the name of the keyed file.
55 
56         Since the backend storage may be folders, or it may use pseudo-folders,
57         make sure the filename doesn't include any path separators.
58         """
59         file_name = key.replace("..", "").strip("/ ")
60         file_name = file_name.replace(os.sep, "_")
61         return file_name
62 
63     def _get_file_path(self, key):
64         """
65         Returns the path to the keyed file, including the storage prefix.
66         """
67         path = self._get_key_name(self._get_file_name(key))
68         return path
69
```
--- 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/openassessment/fileupload/backends/django_storage.py b/openassessment/fileupload/backends/django_storage.py
--- a/openassessment/fileupload/backends/django_storage.py
+++ b/openassessment/fileupload/backends/django_storage.py
@@ -2,7 +2,7 @@
 
 from django.core.files.base import ContentFile
 from django.core.files.storage import default_storage
-from django.core.urlresolvers import reverse_lazy
+from django.core.urlresolvers import reverse
 
 from .base import BaseBackend
 
@@ -15,7 +15,7 @@
         """
         Return the URL pointing to the ORA2 django storage upload endpoint.
         """
-        return reverse_lazy("openassessment-django-storage", kwargs={'key': key})
+        return reverse("openassessment-django-storage", kwargs={'key': key})
 
     def get_download_url(self, key):
         """
diff --git a/openassessment/fileupload/backends/filesystem.py b/openassessment/fileupload/backends/filesystem.py
--- a/openassessment/fileupload/backends/filesystem.py
+++ b/openassessment/fileupload/backends/filesystem.py
@@ -1,6 +1,6 @@
 from django.conf import settings
 import django.core.cache
-from django.core.urlresolvers import reverse_lazy
+from django.core.urlresolvers import reverse
 from django.utils.encoding import smart_text
 
 from .. import exceptions
@@ -47,7 +47,7 @@
 
     def _get_url(self, key):
         key_name = self._get_key_name(key)
-        url = reverse_lazy("openassessment-filesystem-storage", kwargs={'key': key_name})
+        url = reverse("openassessment-filesystem-storage", kwargs={'key': key_name})
         return url
 
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,7 @@
 
 setup(
     name='ora2',
-    version='2.2.1',
+    version='2.2.2',
     author='edX',
     url='http://github.com/edx/edx-ora2',
     description='edx-ora2',

{"golden_diff": "diff --git a/openassessment/fileupload/backends/django_storage.py b/openassessment/fileupload/backends/django_storage.py\n--- a/openassessment/fileupload/backends/django_storage.py\n+++ b/openassessment/fileupload/backends/django_storage.py\n@@ -2,7 +2,7 @@\n \n from django.core.files.base import ContentFile\n from django.core.files.storage import default_storage\n-from django.core.urlresolvers import reverse_lazy\n+from django.core.urlresolvers import reverse\n \n from .base import BaseBackend\n \n@@ -15,7 +15,7 @@\n         \"\"\"\n         Return the URL pointing to the ORA2 django storage upload endpoint.\n         \"\"\"\n-        return reverse_lazy(\"openassessment-django-storage\", kwargs={'key': key})\n+        return reverse(\"openassessment-django-storage\", kwargs={'key': key})\n \n     def get_download_url(self, key):\n         \"\"\"\ndiff --git a/openassessment/fileupload/backends/filesystem.py b/openassessment/fileupload/backends/filesystem.py\n--- a/openassessment/fileupload/backends/filesystem.py\n+++ b/openassessment/fileupload/backends/filesystem.py\n@@ -1,6 +1,6 @@\n from django.conf import settings\n import django.core.cache\n-from django.core.urlresolvers import reverse_lazy\n+from django.core.urlresolvers import reverse\n from django.utils.encoding import smart_text\n \n from .. import exceptions\n@@ -47,7 +47,7 @@\n \n     def _get_url(self, key):\n         key_name = self._get_key_name(key)\n-        url = reverse_lazy(\"openassessment-filesystem-storage\", kwargs={'key': key_name})\n+        url = reverse(\"openassessment-filesystem-storage\", kwargs={'key': key_name})\n         return url\n \n \ndiff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -34,7 +34,7 @@\n \n setup(\n     name='ora2',\n-    version='2.2.1',\n+    version='2.2.2',\n     author='edX',\n     url='http://github.com/edx/edx-ora2',\n     description='edx-ora2',\n", "issue": "\"TypeError: u'<url>' is not JSON serializable\" on upload to backends other than S3\nFile upload to \"django\" and \"filesystem\" backends is currently broken. Each attempt to generate an upload URL fails with the following error:\r\n\r\n```\r\nTraceback (most recent call last):                                                                                                                            \r\n  File \"/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py\", line 41, in inner                                                          \r\n    response = get_response(request)                                                                                                                          \r\n  File \"/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py\", line 249, in _legacy_get_response                                               \r\n    response = self._get_response(request)                                                                                                                    \r\n  File \"/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py\", line 187, in _get_response                                                      \r\n    response = self.process_exception_by_middleware(e, request)                                                                                               \r\n  File \"/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py\", line 185, in _get_response                                                      \r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)                                                                                   \r\n  File \"/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py\", line 185, in inner                                                                \r\n    return func(*args, **kwargs)                                                                                                                              \r\n  File \"/openedx/edx-platform/lms/djangoapps/courseware/module_render.py\", line 962, in handle_xblock_callback                                                \r\n    return _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, course=course)                                                               \r\n  File \"/openedx/edx-platform/lms/djangoapps/courseware/module_render.py\", line 1068, in _invoke_xblock_handler                                               \r\n    resp = instance.handle(handler, req, suffix)                                                                                                              \r\n  File \"/usr/local/lib/python2.7/dist-packages/xblock/mixins.py\", line 90, in handle                                                                          \r\n    return self.runtime.handle(self, handler_name, request, suffix)                                                                                           \r\n  File \"/openedx/edx-platform/common/lib/xmodule/xmodule/x_module.py\", line 1347, in handle                                                                   \r\n    return super(MetricsMixin, self).handle(block, handler_name, request, suffix=suffix)                                                                      \r\n  File \"/usr/local/lib/python2.7/dist-packages/xblock/runtime.py\", line 1037, in handle                                                                       \r\n    results = handler(request, suffix)                                                                                                                        \r\n  File \"/usr/local/lib/python2.7/dist-packages/xblock/mixins.py\", line 74, in wrapper                                                                         \r\n    response = json.dumps(response)                                                                                                                           \r\n  File \"/usr/lib/python2.7/json/__init__.py\", line 244, in dumps                                                                                              \r\n    return _default_encoder.encode(obj)    \r\n  File \"/usr/lib/python2.7/json/encoder.py\", line 207, in encode\r\n    chunks = self.iterencode(o, _one_shot=True)\r\n  File \"/usr/lib/python2.7/json/encoder.py\", line 270, in iterencode\r\n    return _iterencode(o, 0)\r\n  File \"/usr/lib/python2.7/json/encoder.py\", line 184, in default\r\n    raise TypeError(repr(o) + \" is not JSON serializable\")\r\nTypeError: u'/openassessment/fileupload/django/4dd623a62f4e626d827277cd3fedaf45/course-v1:org+video1+01/block-v1:org+video1+01+type@openassessment+block@25d85\r\n51f741342ac919590db2e72091b/' is not JSON serializable\r\n```\r\n\r\nThis error is due to the fact that urls returned by 'django' and 'filesystem' backends are computed with `django.core.urlresolvers.reverse_lazy`. Thus, they are not unicode, but `django.utils.functional.__proxy__` objects. The TypeError is raised when calling `json.dumps()` on `{'success': True, 'url': url_object}` in `xblock.mixins.HandlersMixin.json_handler`.\r\n\r\nI can easily solve the problem by replacing `reverse_lazy` by `reverse`. However, I wonder what was the original reason to use `reverse_lazy`? The change was introduced in commit 3e13d27df by @efischer19.\r\n\r\nPython tests pass successfully if I replace `reverse_lazy` by `reverse`.\r\n\r\nI believe both ORA2 backends are broken for the current Open edX Hawthorn release. \r\n \r\n(this error was first discovered [here](https://github.com/regisb/openedx-docker/issues/97))\n", "before_files": [{"content": "#!/usr/bin/env python\nfrom setuptools import find_packages, setup\n\n\ndef is_requirement(line):\n    \"\"\"\n    Return True if the requirement line is a package requirement;\n    that is, it is not blank, a comment, or editable.\n    \"\"\"\n    # Remove whitespace at the start/end of the line\n    line = line.strip()\n\n    # Skip blank lines, comments, and editable installs\n    return not (\n        line == '' or\n        line.startswith('-r') or\n        line.startswith('#') or\n        line.startswith('-e') or\n        line.startswith('git+')\n    )\n\ndef load_requirements(*requirements_paths):\n    \"\"\"\n    Load all requirements from the specified requirements files.\n    Returns a list of requirement strings.\n    \"\"\"\n    requirements = set()\n    for path in requirements_paths:\n        requirements.update(\n            line.strip() for line in open(path).readlines()\n            if is_requirement(line)\n        )\n    return list(requirements)\n\nsetup(\n    name='ora2',\n    version='2.2.1',\n    author='edX',\n    url='http://github.com/edx/edx-ora2',\n    description='edx-ora2',\n    license='AGPL',\n    classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Framework :: Django :: 1.11',\n        'Intended Audience :: Developers',\n        'License :: OSI Approved :: GNU Affero General Public License v3',\n        'Operating System :: OS Independent',\n        'Programming Language :: Python',\n    ],\n    packages=find_packages(include=['openassessment*'], exclude=['*.test', '*.tests']),\n    include_package_data=True,\n    install_requires=load_requirements('requirements/base.txt', \"requirements/django.txt\"),\n    tests_require=load_requirements('requirements/test.txt'),\n    entry_points={\n        'xblock.v1': [\n            'openassessment = openassessment.xblock.openassessmentblock:OpenAssessmentBlock',\n        ]\n    },\n)\n", "path": "setup.py"}, {"content": "from django.conf import settings\nimport django.core.cache\nfrom django.core.urlresolvers import reverse_lazy\nfrom django.utils.encoding import smart_text\n\nfrom .. import exceptions\nfrom .base import BaseBackend\n\n\nclass Backend(BaseBackend):\n    \"\"\"\n    Upload openassessment student files to a local filesystem. Note\n    that in order to use this file storage backend, you need to include the\n    urls from openassessment.fileupload in your urls.py file:\n\n    E.g:\n        url(r'^openassessment/storage', include(openassessment.fileupload.urls)),\n\n    The ORA2_FILEUPLOAD_CACHE_NAME setting will also have to be defined for the\n    name of the django.core.cache instance which will maintain the list of\n    active storage URLs.\n\n    E.g:\n\n        ORA2_FILEUPLOAD_CACHE_NAME = \"ora2-storage\"\n        CACHES = {\n            ...\n            'ora2-storage': {\n                'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',\n                ...\n            },\n            ...\n        }\n    \"\"\"\n\n    def get_upload_url(self, key, content_type):\n        make_upload_url_available(self._get_key_name(key), self.UPLOAD_URL_TIMEOUT)\n        return self._get_url(key)\n\n    def get_download_url(self, key):\n        make_download_url_available(self._get_key_name(key), self.DOWNLOAD_URL_TIMEOUT)\n        return self._get_url(key)\n\n    def remove_file(self, key):\n        from openassessment.fileupload.views_filesystem import safe_remove, get_file_path\n        return safe_remove(get_file_path(self._get_key_name(key)))\n\n    def _get_url(self, key):\n        key_name = self._get_key_name(key)\n        url = reverse_lazy(\"openassessment-filesystem-storage\", kwargs={'key': key_name})\n        return url\n\n\ndef get_cache():\n    \"\"\"\n    Returns a django.core.cache instance in charge of maintaining the\n    authorized upload and download URL.\n\n    Raises:\n        FileUploadInternalError if the cache name setting is not defined.\n        InvalidCacheBackendError if the corresponding cache backend has not\n        been configured.\n    \"\"\"\n    cache_name = getattr(settings, \"ORA2_FILEUPLOAD_CACHE_NAME\", None)\n    if cache_name is None:\n        raise exceptions.FileUploadInternalError(\"Undefined cache backend for file upload\")\n    return django.core.cache.caches[cache_name]\n\n\ndef make_upload_url_available(url_key_name, timeout):\n    \"\"\"\n    Authorize an upload URL.\n\n    Arguments:\n        url_key_name (str): key that uniquely identifies the upload url\n        timeout (int): time in seconds before the url expires\n    \"\"\"\n    get_cache().set(\n        smart_text(get_upload_cache_key(url_key_name)),\n        1, timeout\n    )\n\n\ndef make_download_url_available(url_key_name, timeout):\n    \"\"\"\n    Authorize a download URL.\n\n    Arguments:\n        url_key_name (str): key that uniquely identifies the url\n        timeout (int): time in seconds before the url expires\n    \"\"\"\n    get_cache().set(\n        smart_text(get_download_cache_key(url_key_name)),\n        1, timeout\n    )\n\n\ndef is_upload_url_available(url_key_name):\n    \"\"\"\n    Return True if the corresponding upload URL is available.\n    \"\"\"\n    return get_cache().get(smart_text(get_upload_cache_key(url_key_name))) is not None\n\n\ndef is_download_url_available(url_key_name):\n    \"\"\"\n    Return True if the corresponding download URL is available.\n    \"\"\"\n    return get_cache().get(smart_text(get_download_cache_key(url_key_name))) is not None\n\n\ndef get_upload_cache_key(url_key_name):\n    return \"upload/\" + url_key_name\n\n\ndef get_download_cache_key(url_key_name):\n    return \"download/\" + url_key_name\n", "path": "openassessment/fileupload/backends/filesystem.py"}, {"content": "import os\n\nfrom django.core.files.base import ContentFile\nfrom django.core.files.storage import default_storage\nfrom django.core.urlresolvers import reverse_lazy\n\nfrom .base import BaseBackend\n\n\nclass Backend(BaseBackend):\n    \"\"\"\n    Manage openassessment student files uploaded using the default django storage settings.\n    \"\"\"\n    def get_upload_url(self, key, content_type):\n        \"\"\"\n        Return the URL pointing to the ORA2 django storage upload endpoint.\n        \"\"\"\n        return reverse_lazy(\"openassessment-django-storage\", kwargs={'key': key})\n\n    def get_download_url(self, key):\n        \"\"\"\n        Return the django storage download URL for the given key.\n\n        Returns None if no file exists at that location.\n        \"\"\"\n        path = self._get_file_path(key)\n        if default_storage.exists(path):\n            return default_storage.url(path)\n        return None\n\n    def upload_file(self, key, content):\n        \"\"\"\n        Upload the given file content to the keyed location.\n        \"\"\"\n        path = self._get_file_path(key)\n        saved_path = default_storage.save(path, ContentFile(content))\n        return saved_path\n\n    def remove_file(self, key):\n        \"\"\"\n        Remove the file at the given keyed location.\n\n        Returns True if the file exists, and was removed.\n        Returns False if the file does not exist, and so was not removed.\n        \"\"\"\n        path = self._get_file_path(key)\n        if default_storage.exists(path):\n            default_storage.delete(path)\n            return True\n        return False\n\n    def _get_file_name(self, key):\n        \"\"\"\n        Returns the name of the keyed file.\n\n        Since the backend storage may be folders, or it may use pseudo-folders,\n        make sure the filename doesn't include any path separators.\n        \"\"\"\n        file_name = key.replace(\"..\", \"\").strip(\"/ \")\n        file_name = file_name.replace(os.sep, \"_\")\n        return file_name\n\n    def _get_file_path(self, key):\n        \"\"\"\n        Returns the path to the keyed file, including the storage prefix.\n        \"\"\"\n        path = self._get_key_name(self._get_file_name(key))\n        return path\n", "path": "openassessment/fileupload/backends/django_storage.py"}], "after_files": [{"content": "#!/usr/bin/env python\nfrom setuptools import find_packages, setup\n\n\ndef is_requirement(line):\n    \"\"\"\n    Return True if the requirement line is a package requirement;\n    that is, it is not blank, a comment, or editable.\n    \"\"\"\n    # Remove whitespace at the start/end of the line\n    line = line.strip()\n\n    # Skip blank lines, comments, and editable installs\n    return not (\n        line == '' or\n        line.startswith('-r') or\n        line.startswith('#') or\n        line.startswith('-e') or\n        line.startswith('git+')\n    )\n\ndef load_requirements(*requirements_paths):\n    \"\"\"\n    Load all requirements from the specified requirements files.\n    Returns a list of requirement strings.\n    \"\"\"\n    requirements = set()\n    for path in requirements_paths:\n        requirements.update(\n            line.strip() for line in open(path).readlines()\n            if is_requirement(line)\n        )\n    return list(requirements)\n\nsetup(\n    name='ora2',\n    version='2.2.2',\n    author='edX',\n    url='http://github.com/edx/edx-ora2',\n    description='edx-ora2',\n    license='AGPL',\n    classifiers=[\n        'Development Status :: 3 - Alpha',\n        'Framework :: Django :: 1.11',\n        'Intended Audience :: Developers',\n        'License :: OSI Approved :: GNU Affero General Public License v3',\n        'Operating System :: OS Independent',\n        'Programming Language :: Python',\n    ],\n    packages=find_packages(include=['openassessment*'], exclude=['*.test', '*.tests']),\n    include_package_data=True,\n    install_requires=load_requirements('requirements/base.txt', \"requirements/django.txt\"),\n    tests_require=load_requirements('requirements/test.txt'),\n    entry_points={\n        'xblock.v1': [\n            'openassessment = openassessment.xblock.openassessmentblock:OpenAssessmentBlock',\n        ]\n    },\n)\n", "path": "setup.py"}, {"content": "from django.conf import settings\nimport django.core.cache\nfrom django.core.urlresolvers import reverse\nfrom django.utils.encoding import smart_text\n\nfrom .. import exceptions\nfrom .base import BaseBackend\n\n\nclass Backend(BaseBackend):\n    \"\"\"\n    Upload openassessment student files to a local filesystem. Note\n    that in order to use this file storage backend, you need to include the\n    urls from openassessment.fileupload in your urls.py file:\n\n    E.g:\n        url(r'^openassessment/storage', include(openassessment.fileupload.urls)),\n\n    The ORA2_FILEUPLOAD_CACHE_NAME setting will also have to be defined for the\n    name of the django.core.cache instance which will maintain the list of\n    active storage URLs.\n\n    E.g:\n\n        ORA2_FILEUPLOAD_CACHE_NAME = \"ora2-storage\"\n        CACHES = {\n            ...\n            'ora2-storage': {\n                'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',\n                ...\n            },\n            ...\n        }\n    \"\"\"\n\n    def get_upload_url(self, key, content_type):\n        make_upload_url_available(self._get_key_name(key), self.UPLOAD_URL_TIMEOUT)\n        return self._get_url(key)\n\n    def get_download_url(self, key):\n        make_download_url_available(self._get_key_name(key), self.DOWNLOAD_URL_TIMEOUT)\n        return self._get_url(key)\n\n    def remove_file(self, key):\n        from openassessment.fileupload.views_filesystem import safe_remove, get_file_path\n        return safe_remove(get_file_path(self._get_key_name(key)))\n\n    def _get_url(self, key):\n        key_name = self._get_key_name(key)\n        url = reverse(\"openassessment-filesystem-storage\", kwargs={'key': key_name})\n        return url\n\n\ndef get_cache():\n    \"\"\"\n    Returns a django.core.cache instance in charge of maintaining the\n    authorized upload and download URL.\n\n    Raises:\n        FileUploadInternalError if the cache name setting is not defined.\n        InvalidCacheBackendError if the corresponding cache backend has not\n        been configured.\n    \"\"\"\n    cache_name = getattr(settings, \"ORA2_FILEUPLOAD_CACHE_NAME\", None)\n    if cache_name is None:\n        raise exceptions.FileUploadInternalError(\"Undefined cache backend for file upload\")\n    return django.core.cache.caches[cache_name]\n\n\ndef make_upload_url_available(url_key_name, timeout):\n    \"\"\"\n    Authorize an upload URL.\n\n    Arguments:\n        url_key_name (str): key that uniquely identifies the upload url\n        timeout (int): time in seconds before the url expires\n    \"\"\"\n    get_cache().set(\n        smart_text(get_upload_cache_key(url_key_name)),\n        1, timeout\n    )\n\n\ndef make_download_url_available(url_key_name, timeout):\n    \"\"\"\n    Authorize a download URL.\n\n    Arguments:\n        url_key_name (str): key that uniquely identifies the url\n        timeout (int): time in seconds before the url expires\n    \"\"\"\n    get_cache().set(\n        smart_text(get_download_cache_key(url_key_name)),\n        1, timeout\n    )\n\n\ndef is_upload_url_available(url_key_name):\n    \"\"\"\n    Return True if the corresponding upload URL is available.\n    \"\"\"\n    return get_cache().get(smart_text(get_upload_cache_key(url_key_name))) is not None\n\n\ndef is_download_url_available(url_key_name):\n    \"\"\"\n    Return True if the corresponding download URL is available.\n    \"\"\"\n    return get_cache().get(smart_text(get_download_cache_key(url_key_name))) is not None\n\n\ndef get_upload_cache_key(url_key_name):\n    return \"upload/\" + url_key_name\n\n\ndef get_download_cache_key(url_key_name):\n    return \"download/\" + url_key_name\n", "path": "openassessment/fileupload/backends/filesystem.py"}, {"content": "import os\n\nfrom django.core.files.base import ContentFile\nfrom django.core.files.storage import default_storage\nfrom django.core.urlresolvers import reverse\n\nfrom .base import BaseBackend\n\n\nclass Backend(BaseBackend):\n    \"\"\"\n    Manage openassessment student files uploaded using the default django storage settings.\n    \"\"\"\n    def get_upload_url(self, key, content_type):\n        \"\"\"\n        Return the URL pointing to the ORA2 django storage upload endpoint.\n        \"\"\"\n        return reverse(\"openassessment-django-storage\", kwargs={'key': key})\n\n    def get_download_url(self, key):\n        \"\"\"\n        Return the django storage download URL for the given key.\n\n        Returns None if no file exists at that location.\n        \"\"\"\n        path = self._get_file_path(key)\n        if default_storage.exists(path):\n            return default_storage.url(path)\n        return None\n\n    def upload_file(self, key, content):\n        \"\"\"\n        Upload the given file content to the keyed location.\n        \"\"\"\n        path = self._get_file_path(key)\n        saved_path = default_storage.save(path, ContentFile(content))\n        return saved_path\n\n    def remove_file(self, key):\n        \"\"\"\n        Remove the file at the given keyed location.\n\n        Returns True if the file exists, and was removed.\n        Returns False if the file does not exist, and so was not removed.\n        \"\"\"\n        path = self._get_file_path(key)\n        if default_storage.exists(path):\n            default_storage.delete(path)\n            return True\n        return False\n\n    def _get_file_name(self, key):\n        \"\"\"\n        Returns the name of the keyed file.\n\n        Since the backend storage may be folders, or it may use pseudo-folders,\n        make sure the filename doesn't include any path separators.\n        \"\"\"\n        file_name = key.replace(\"..\", \"\").strip(\"/ \")\n        file_name = file_name.replace(os.sep, \"_\")\n        return file_name\n\n    def _get_file_path(self, key):\n        \"\"\"\n        Returns the path to the keyed file, including the storage prefix.\n        \"\"\"\n        path = self._get_key_name(self._get_file_name(key))\n        return path\n", "path": "openassessment/fileupload/backends/django_storage.py"}]}