Repository: openneuroorg/openneuro
Issue: Accent characters in dataset_description edits are replaced with unicode escape sequences

**Describe the bug**
Continuation of https://github.com/OpenNeuroOrg/openneuro/issues/2622

The previous fix resolved the ability for accent characters to render on the dataset landing page. However, now their associated data in the dataset_description.json become not human readable. This is seen on the `authors` and `ethicsapproval` fields. 

**To Reproduce**
Steps to reproduce the behavior:
1. Go to https://openneuro.org/datasets/ds004168/file-display/dataset_description.json
 
The web rendering of the accent characters is correct, but the underlying data is not



Changed files:
services/datalad/datalad_service/tasks/description.py, services/datalad/tests/test_description.py

diff --git a/services/datalad/datalad_service/tasks/description.py b/services/datalad/datalad_service/tasks/description.py
index f387775f6..6385c1caf 100644
--- a/services/datalad/datalad_service/tasks/description.py
+++ b/services/datalad/datalad_service/tasks/description.py
@@ -30,7 +30,8 @@ def update_description(store, dataset, description_fields, name=None, email=None
                                 description, description_file_contents)
             description_file.seek(0)
             description_file.truncate(0)
-            description_file.write(json.dumps(updated, indent=4))
+            description_file.write(json.dumps(
+                updated, indent=4, ensure_ascii=False))
         # Commit new content, run validator
         commit_files(store, dataset, [
             'dataset_description.json'])
diff --git a/services/datalad/tests/test_description.py b/services/datalad/tests/test_description.py
index bd49d383f..5efcf0cae 100644
--- a/services/datalad/tests/test_description.py
+++ b/services/datalad/tests/test_description.py
@@ -30,9 +30,7 @@ def test_update(client, new_dataset):
     assert ds_description[key] == value
 
 
-def post_and_check_description(client, new_dataset, base_description):
-    key = 'Name'
-    value = 'Guthrum'
+def post_and_check_description(client, new_dataset, base_description, key="Name", value="Guthrum"):
     body = json.dumps({
         'description_fields': {
             key: value
@@ -58,33 +56,53 @@ def post_and_check_description(client, new_dataset, base_description):
     check_response = client.simulate_get(
         '/datasets/{}/files/dataset_description.json'.format(ds_id))
     assert check_response.status == falcon.HTTP_OK
-    ds_description = json.loads(check_response.content)
-    assert ds_description[key] == value
+    return check_response.content
 
 
 def test_update_with_trailing_newline(client, new_dataset):
     base_description = '{ "json stuff": "True", "Name": "Uhtred" }\\n'
-    post_and_check_description(client, new_dataset, base_description)
+    content = post_and_check_description(client, new_dataset, base_description)
+    ds_description = json.loads(content)
+    assert ds_description["Name"] == "Guthrum"
 
 
 def test_update_with_trailing_double_newline(client, new_dataset):
     base_description = '{ "json stuff": "True", "Name": "Uhtred" }\\n\\n'
-    post_and_check_description(client, new_dataset, base_description)
+    content = post_and_check_description(client, new_dataset, base_description)
+    ds_description = json.loads(content)
+    assert ds_description["Name"] == "Guthrum"
 
 
 def test_update_with_trailing_windows_newline(client, new_dataset):
     base_description = '{ "json stuff": "True", "Name": "Uhtred" }\\r\\n'
-    post_and_check_description(client, new_dataset, base_description)
+    content = post_and_check_description(client, new_dataset, base_description)
+    ds_description = json.loads(content)
+    assert ds_description["Name"] == "Guthrum"
 
 
 def test_update_with_trailing_mac_newline(client, new_dataset):
     base_description = '{ "json stuff": "True", "Name": "Uhtred" }\\r'
-    post_and_check_description(client, new_dataset, base_description)
+    content = post_and_check_description(client, new_dataset, base_description)
+    ds_description = json.loads(content)
+    assert ds_description["Name"] == "Guthrum"
 
 
 def test_update_with_trailing_wat_newline(client, new_dataset):
     base_description = '{ "json stuff": "True", "Name": "Uhtred" }\\n\\r'
-    post_and_check_description(client, new_dataset, base_description)
+    content = post_and_check_description(client, new_dataset, base_description)
+    ds_description = json.loads(content)
+    assert ds_description["Name"] == "Guthrum"
+
+
+def test_update_with_unicode_characters(client, new_dataset):
+    base_description = '{ "json stuff": "True", "Name": "Uhtred", "Authors": ["香母酢"] }\\n'
+    content = post_and_check_description(
+        client, new_dataset, base_description, "Name", "柴犬").decode()
+    # Verify that escaped characters did not make it into the file
+    assert '\\\\u67f4' not in content
+    assert '\\\\u72ac' not in content
+    ds_description = json.loads(content)
+    assert ds_description["Authors"][0] == "香母酢"
 
 
 def test_description_formatting(client, new_dataset):