handlers.py
102 lines
| 2.7 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r18704 | """Tornado handlers for frontend config storage.""" | ||
Thomas Kluyver
|
r18703 | |||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
import json | ||||
import os | ||||
import io | ||||
Thomas Kluyver
|
r18812 | import errno | ||
Thomas Kluyver
|
r18703 | from tornado import web | ||
Thomas Kluyver
|
r18706 | from IPython.utils.py3compat import PY3 | ||
Thomas Kluyver
|
r18703 | from ...base.handlers import IPythonHandler, json_errors | ||
Thomas Kluyver
|
r18705 | def recursive_update(target, new): | ||
"""Recursively update one dictionary using another. | ||||
None values will delete their keys. | ||||
""" | ||||
for k, v in new.items(): | ||||
if isinstance(v, dict): | ||||
if k not in target: | ||||
target[k] = {} | ||||
recursive_update(target[k], v) | ||||
if not target[k]: | ||||
# Prune empty subdicts | ||||
del target[k] | ||||
elif v is None: | ||||
target.pop(k, None) | ||||
else: | ||||
target[k] = v | ||||
Thomas Kluyver
|
r18703 | |||
class ConfigHandler(IPythonHandler): | ||||
SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH') | ||||
Thomas Kluyver
|
r18812 | @property | ||
def config_dir(self): | ||||
return os.path.join(self.profile_dir, 'nbconfig') | ||||
def ensure_config_dir_exists(self): | ||||
try: | ||||
os.mkdir(self.config_dir, 0o755) | ||||
except OSError as e: | ||||
if e.errno != errno.EEXIST: | ||||
raise | ||||
Thomas Kluyver
|
r18703 | def file_name(self, section_name): | ||
Thomas Kluyver
|
r18812 | return os.path.join(self.config_dir, section_name+'.json') | ||
Thomas Kluyver
|
r18703 | |||
@web.authenticated | ||||
@json_errors | ||||
def get(self, section_name): | ||||
self.set_header("Content-Type", 'application/json') | ||||
filename = self.file_name(section_name) | ||||
if os.path.isfile(filename): | ||||
with io.open(filename, encoding='utf-8') as f: | ||||
self.finish(f.read()) | ||||
else: | ||||
self.finish("{}") | ||||
@web.authenticated | ||||
@json_errors | ||||
def put(self, section_name): | ||||
Thomas Kluyver
|
r18704 | self.get_json_body() # Will raise 400 if content is not valid JSON | ||
Thomas Kluyver
|
r18703 | filename = self.file_name(section_name) | ||
Thomas Kluyver
|
r18812 | self.ensure_config_dir_exists() | ||
Thomas Kluyver
|
r18703 | with open(filename, 'wb') as f: | ||
f.write(self.request.body) | ||||
self.set_status(204) | ||||
@web.authenticated | ||||
@json_errors | ||||
def patch(self, section_name): | ||||
filename = self.file_name(section_name) | ||||
if os.path.isfile(filename): | ||||
with io.open(filename, encoding='utf-8') as f: | ||||
section = json.load(f) | ||||
else: | ||||
section = {} | ||||
Thomas Kluyver
|
r18705 | update = self.get_json_body() | ||
recursive_update(section, update) | ||||
Thomas Kluyver
|
r18703 | |||
Thomas Kluyver
|
r18812 | self.ensure_config_dir_exists() | ||
Thomas Kluyver
|
r18706 | if PY3: | ||
f = io.open(filename, 'w', encoding='utf-8') | ||||
else: | ||||
f = open(filename, 'wb') | ||||
with f: | ||||
Thomas Kluyver
|
r18703 | json.dump(section, f) | ||
Thomas Kluyver
|
r18706 | |||
Thomas Kluyver
|
r18707 | self.finish(json.dumps(section)) | ||
Thomas Kluyver
|
r18703 | |||
# URL to handler mappings | ||||
section_name_regex = r"(?P<section_name>\w+)" | ||||
default_handlers = [ | ||||
(r"/api/config/%s" % section_name_regex, ConfigHandler), | ||||
] | ||||