mirror of
https://github.com/jupyter/notebook.git
synced 2024-12-27 04:20:22 +08:00
First stab at ConfigManager class
This commit is contained in:
parent
cf91873644
commit
febd670716
@ -175,6 +175,10 @@ class IPythonHandler(AuthenticatedHandler):
|
||||
def kernel_spec_manager(self):
|
||||
return self.settings['kernel_spec_manager']
|
||||
|
||||
@property
|
||||
def config_manager(self):
|
||||
return self.settings['config_manager']
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# CORS
|
||||
#---------------------------------------------------------------
|
||||
|
@ -125,19 +125,21 @@ def load_handlers(name):
|
||||
class NotebookWebApplication(web.Application):
|
||||
|
||||
def __init__(self, ipython_app, kernel_manager, contents_manager,
|
||||
cluster_manager, session_manager, kernel_spec_manager, log,
|
||||
cluster_manager, session_manager, kernel_spec_manager,
|
||||
config_manager, log,
|
||||
base_url, default_url, settings_overrides, jinja_env_options):
|
||||
|
||||
settings = self.init_settings(
|
||||
ipython_app, kernel_manager, contents_manager, cluster_manager,
|
||||
session_manager, kernel_spec_manager, log, base_url, default_url,
|
||||
settings_overrides, jinja_env_options)
|
||||
session_manager, kernel_spec_manager, config_manager, log, base_url,
|
||||
default_url, settings_overrides, jinja_env_options)
|
||||
handlers = self.init_handlers(settings)
|
||||
|
||||
super(NotebookWebApplication, self).__init__(handlers, **settings)
|
||||
|
||||
def init_settings(self, ipython_app, kernel_manager, contents_manager,
|
||||
cluster_manager, session_manager, kernel_spec_manager,
|
||||
config_manager,
|
||||
log, base_url, default_url, settings_overrides,
|
||||
jinja_env_options=None):
|
||||
|
||||
@ -172,6 +174,7 @@ class NotebookWebApplication(web.Application):
|
||||
cluster_manager=cluster_manager,
|
||||
session_manager=session_manager,
|
||||
kernel_spec_manager=kernel_spec_manager,
|
||||
config_manager=config_manager,
|
||||
|
||||
# IPython stuff
|
||||
nbextensions_path = ipython_app.nbextensions_path,
|
||||
@ -607,6 +610,11 @@ class NotebookApp(BaseIPythonApplication):
|
||||
help='The cluster manager class to use.'
|
||||
)
|
||||
|
||||
config_manager_class = DottedObjectName('IPython.html.services.config.manager.ConfigManager',
|
||||
config = True,
|
||||
help='The config manager class to use'
|
||||
)
|
||||
|
||||
kernel_spec_manager = Instance(KernelSpecManager)
|
||||
|
||||
def _kernel_spec_manager_default(self):
|
||||
@ -722,6 +730,10 @@ class NotebookApp(BaseIPythonApplication):
|
||||
self.cluster_manager = kls(parent=self, log=self.log)
|
||||
self.cluster_manager.update_profiles()
|
||||
|
||||
kls = import_item(self.config_manager_class)
|
||||
self.config_manager = kls(parent=self, log=self.log,
|
||||
profile_dir=self.profile_dir.location)
|
||||
|
||||
def init_logging(self):
|
||||
# This prevents double log messages because tornado use a root logger that
|
||||
# self.log is a child of. The logging module dipatches log messages to a log
|
||||
@ -747,6 +759,7 @@ class NotebookApp(BaseIPythonApplication):
|
||||
self.web_app = NotebookWebApplication(
|
||||
self, self.kernel_manager, self.contents_manager,
|
||||
self.cluster_manager, self.session_manager, self.kernel_spec_manager,
|
||||
self.config_manager,
|
||||
self.log, self.base_url, self.default_url, self.tornado_settings,
|
||||
self.jinja_environment_options
|
||||
)
|
||||
|
@ -11,85 +11,27 @@ from tornado import web
|
||||
from IPython.utils.py3compat import PY3
|
||||
from ...base.handlers import IPythonHandler, json_errors
|
||||
|
||||
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
|
||||
|
||||
class ConfigHandler(IPythonHandler):
|
||||
SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH')
|
||||
|
||||
@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
|
||||
|
||||
def file_name(self, section_name):
|
||||
return os.path.join(self.config_dir, section_name+'.json')
|
||||
|
||||
@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("{}")
|
||||
self.finish(json.dumps(self.config_manager.get(section_name)))
|
||||
|
||||
@web.authenticated
|
||||
@json_errors
|
||||
def put(self, section_name):
|
||||
self.get_json_body() # Will raise 400 if content is not valid JSON
|
||||
filename = self.file_name(section_name)
|
||||
self.ensure_config_dir_exists()
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(self.request.body)
|
||||
data = self.get_json_body() # Will raise 400 if content is not valid JSON
|
||||
self.config_manager.set(section_name, data)
|
||||
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 = {}
|
||||
|
||||
update = self.get_json_body()
|
||||
recursive_update(section, update)
|
||||
|
||||
self.ensure_config_dir_exists()
|
||||
if PY3:
|
||||
f = io.open(filename, 'w', encoding='utf-8')
|
||||
else:
|
||||
f = open(filename, 'wb')
|
||||
with f:
|
||||
json.dump(section, f)
|
||||
|
||||
new_data = self.get_json_body()
|
||||
section = self.config_manager.update(section_name, new_data)
|
||||
self.finish(json.dumps(section))
|
||||
|
||||
|
||||
|
87
IPython/html/services/config/manager.py
Normal file
87
IPython/html/services/config/manager.py
Normal file
@ -0,0 +1,87 @@
|
||||
"""Manager to read and modify frontend config data in JSON files.
|
||||
"""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
import errno
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
|
||||
from IPython.config import LoggingConfigurable
|
||||
from IPython.utils.py3compat import PY3
|
||||
from IPython.utils.traitlets import Unicode
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
class ConfigManager(LoggingConfigurable):
|
||||
profile_dir = Unicode()
|
||||
|
||||
@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
|
||||
|
||||
def file_name(self, section_name):
|
||||
return os.path.join(self.config_dir, section_name+'.json')
|
||||
|
||||
def get(self, section_name):
|
||||
"""Retrieve the config data for the specified section.
|
||||
|
||||
Returns the data as a dictionary, or an empty dictionary if the file
|
||||
doesn't exist.
|
||||
"""
|
||||
filename = self.file_name(section_name)
|
||||
if os.path.isfile(filename):
|
||||
with io.open(filename, encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
else:
|
||||
return {}
|
||||
|
||||
def set(self, section_name, data):
|
||||
"""Store the given config data.
|
||||
"""
|
||||
filename = self.file_name(section_name)
|
||||
self.ensure_config_dir_exists()
|
||||
|
||||
if PY3:
|
||||
f = io.open(filename, 'w', encoding='utf-8')
|
||||
else:
|
||||
f = open(filename, 'wb')
|
||||
with f:
|
||||
json.dump(data, f)
|
||||
|
||||
def update(self, section_name, new_data):
|
||||
"""Modify the config section by recursively updating it with new_data.
|
||||
|
||||
Returns the modified config data as a dictionary.
|
||||
"""
|
||||
data = self.get(section_name)
|
||||
recursive_update(data, new_data)
|
||||
self.set(section_name, data)
|
||||
return data
|
Loading…
Reference in New Issue
Block a user