Show More
@@ -9,6 +9,25 b' from tornado import web' | |||
|
9 | 9 | |
|
10 | 10 | from ...base.handlers import IPythonHandler, json_errors |
|
11 | 11 | |
|
12 | def recursive_update(target, new): | |
|
13 | """Recursively update one dictionary using another. | |
|
14 | ||
|
15 | None values will delete their keys. | |
|
16 | """ | |
|
17 | for k, v in new.items(): | |
|
18 | if isinstance(v, dict): | |
|
19 | if k not in target: | |
|
20 | target[k] = {} | |
|
21 | recursive_update(target[k], v) | |
|
22 | if not target[k]: | |
|
23 | # Prune empty subdicts | |
|
24 | del target[k] | |
|
25 | ||
|
26 | elif v is None: | |
|
27 | target.pop(k, None) | |
|
28 | ||
|
29 | else: | |
|
30 | target[k] = v | |
|
12 | 31 | |
|
13 | 32 | class ConfigHandler(IPythonHandler): |
|
14 | 33 | SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH') |
@@ -46,11 +65,8 b' class ConfigHandler(IPythonHandler):' | |||
|
46 | 65 | else: |
|
47 | 66 | section = {} |
|
48 | 67 | |
|
49 |
|
|
|
50 | if v is None: | |
|
51 | section.pop(k, None) | |
|
52 | else: | |
|
53 | section[k] = v | |
|
68 | update = self.get_json_body() | |
|
69 | recursive_update(section, update) | |
|
54 | 70 | |
|
55 | 71 | with io.open(filename, 'w', encoding='utf-8') as f: |
|
56 | 72 | json.dump(section, f) |
@@ -1,5 +1,5 b'' | |||
|
1 | 1 | # coding: utf-8 |
|
2 |
"""Test the |
|
|
2 | """Test the config webservice API.""" | |
|
3 | 3 | |
|
4 | 4 | import json |
|
5 | 5 | |
@@ -32,7 +32,7 b' class ConfigAPI(object):' | |||
|
32 | 32 | return self._req('PATCH', section, json.dumps(values)) |
|
33 | 33 | |
|
34 | 34 | class APITest(NotebookTestBase): |
|
35 |
"""Test the |
|
|
35 | """Test the config web service API""" | |
|
36 | 36 | def setUp(self): |
|
37 | 37 | self.config_api = ConfigAPI(self.base_url()) |
|
38 | 38 | |
@@ -46,18 +46,22 b' class APITest(NotebookTestBase):' | |||
|
46 | 46 | self.assertEqual(r.json(), sample) |
|
47 | 47 | |
|
48 | 48 | def test_modify(self): |
|
49 |
sample = {'foo': 'bar', 'baz': 73 |
|
|
49 | sample = {'foo': 'bar', 'baz': 73, | |
|
50 | 'sub': {'a': 6, 'b': 7}, 'sub2': {'c': 8}} | |
|
50 | 51 | self.config_api.set('example', sample) |
|
51 | 52 | |
|
52 | 53 | r = self.config_api.modify('example', {'foo': None, # should delete foo |
|
53 | 54 | 'baz': 75, |
|
54 | 55 | 'wib': [1,2,3], |
|
56 | 'sub': {'a': 8, 'b': None, 'd': 9}, | |
|
57 | 'sub2': {'c': None} # should delete sub2 | |
|
55 | 58 | }) |
|
56 | 59 | self.assertEqual(r.status_code, 204) |
|
57 | 60 | |
|
58 | 61 | r = self.config_api.get('example') |
|
59 | 62 | self.assertEqual(r.status_code, 200) |
|
60 |
self.assertEqual(r.json(), {'baz': 75, 'wib': [1,2,3] |
|
|
63 | self.assertEqual(r.json(), {'baz': 75, 'wib': [1,2,3], | |
|
64 | 'sub': {'a': 8, 'd': 9}}) | |
|
61 | 65 | |
|
62 | 66 | def test_get_unknown(self): |
|
63 | 67 | # We should get an empty config dictionary instead of a 404 |
General Comments 0
You need to be logged in to leave comments.
Login now