##// END OF EJS Templates
Fix writing JSON on Python 2
Thomas Kluyver -
Show More
@@ -1,82 +1,88 b''
1 """Tornado handlers for frontend config storage."""
1 """Tornado handlers for frontend config storage."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 import json
5 import json
6 import os
6 import os
7 import io
7 import io
8 from tornado import web
8 from tornado import web
9
9
10 from IPython.utils.py3compat import PY3
10 from ...base.handlers import IPythonHandler, json_errors
11 from ...base.handlers import IPythonHandler, json_errors
11
12
12 def recursive_update(target, new):
13 def recursive_update(target, new):
13 """Recursively update one dictionary using another.
14 """Recursively update one dictionary using another.
14
15
15 None values will delete their keys.
16 None values will delete their keys.
16 """
17 """
17 for k, v in new.items():
18 for k, v in new.items():
18 if isinstance(v, dict):
19 if isinstance(v, dict):
19 if k not in target:
20 if k not in target:
20 target[k] = {}
21 target[k] = {}
21 recursive_update(target[k], v)
22 recursive_update(target[k], v)
22 if not target[k]:
23 if not target[k]:
23 # Prune empty subdicts
24 # Prune empty subdicts
24 del target[k]
25 del target[k]
25
26
26 elif v is None:
27 elif v is None:
27 target.pop(k, None)
28 target.pop(k, None)
28
29
29 else:
30 else:
30 target[k] = v
31 target[k] = v
31
32
32 class ConfigHandler(IPythonHandler):
33 class ConfigHandler(IPythonHandler):
33 SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH')
34 SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH')
34
35
35 def file_name(self, section_name):
36 def file_name(self, section_name):
36 return os.path.join(self.profile_dir, 'nb_%s_config.json' % section_name)
37 return os.path.join(self.profile_dir, 'nb_%s_config.json' % section_name)
37
38
38 @web.authenticated
39 @web.authenticated
39 @json_errors
40 @json_errors
40 def get(self, section_name):
41 def get(self, section_name):
41 self.set_header("Content-Type", 'application/json')
42 self.set_header("Content-Type", 'application/json')
42 filename = self.file_name(section_name)
43 filename = self.file_name(section_name)
43 if os.path.isfile(filename):
44 if os.path.isfile(filename):
44 with io.open(filename, encoding='utf-8') as f:
45 with io.open(filename, encoding='utf-8') as f:
45 self.finish(f.read())
46 self.finish(f.read())
46 else:
47 else:
47 self.finish("{}")
48 self.finish("{}")
48
49
49 @web.authenticated
50 @web.authenticated
50 @json_errors
51 @json_errors
51 def put(self, section_name):
52 def put(self, section_name):
52 self.get_json_body() # Will raise 400 if content is not valid JSON
53 self.get_json_body() # Will raise 400 if content is not valid JSON
53 filename = self.file_name(section_name)
54 filename = self.file_name(section_name)
54 with open(filename, 'wb') as f:
55 with open(filename, 'wb') as f:
55 f.write(self.request.body)
56 f.write(self.request.body)
56 self.set_status(204)
57 self.set_status(204)
57
58
58 @web.authenticated
59 @web.authenticated
59 @json_errors
60 @json_errors
60 def patch(self, section_name):
61 def patch(self, section_name):
61 filename = self.file_name(section_name)
62 filename = self.file_name(section_name)
62 if os.path.isfile(filename):
63 if os.path.isfile(filename):
63 with io.open(filename, encoding='utf-8') as f:
64 with io.open(filename, encoding='utf-8') as f:
64 section = json.load(f)
65 section = json.load(f)
65 else:
66 else:
66 section = {}
67 section = {}
67
68
68 update = self.get_json_body()
69 update = self.get_json_body()
69 recursive_update(section, update)
70 recursive_update(section, update)
70
71
71 with io.open(filename, 'w', encoding='utf-8') as f:
72 if PY3:
73 f = io.open(filename, 'w', encoding='utf-8')
74 else:
75 f = open(filename, 'wb')
76 with f:
72 json.dump(section, f)
77 json.dump(section, f)
78
73 self.set_status(204)
79 self.set_status(204)
74
80
75
81
76 # URL to handler mappings
82 # URL to handler mappings
77
83
78 section_name_regex = r"(?P<section_name>\w+)"
84 section_name_regex = r"(?P<section_name>\w+)"
79
85
80 default_handlers = [
86 default_handlers = [
81 (r"/api/config/%s" % section_name_regex, ConfigHandler),
87 (r"/api/config/%s" % section_name_regex, ConfigHandler),
82 ]
88 ]
General Comments 0
You need to be logged in to leave comments. Login now