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):
|
def kernel_spec_manager(self):
|
||||||
return self.settings['kernel_spec_manager']
|
return self.settings['kernel_spec_manager']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config_manager(self):
|
||||||
|
return self.settings['config_manager']
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# CORS
|
# CORS
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
|
@ -125,19 +125,21 @@ def load_handlers(name):
|
|||||||
class NotebookWebApplication(web.Application):
|
class NotebookWebApplication(web.Application):
|
||||||
|
|
||||||
def __init__(self, ipython_app, kernel_manager, contents_manager,
|
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):
|
base_url, default_url, settings_overrides, jinja_env_options):
|
||||||
|
|
||||||
settings = self.init_settings(
|
settings = self.init_settings(
|
||||||
ipython_app, kernel_manager, contents_manager, cluster_manager,
|
ipython_app, kernel_manager, contents_manager, cluster_manager,
|
||||||
session_manager, kernel_spec_manager, log, base_url, default_url,
|
session_manager, kernel_spec_manager, config_manager, log, base_url,
|
||||||
settings_overrides, jinja_env_options)
|
default_url, settings_overrides, jinja_env_options)
|
||||||
handlers = self.init_handlers(settings)
|
handlers = self.init_handlers(settings)
|
||||||
|
|
||||||
super(NotebookWebApplication, self).__init__(handlers, **settings)
|
super(NotebookWebApplication, self).__init__(handlers, **settings)
|
||||||
|
|
||||||
def init_settings(self, ipython_app, kernel_manager, contents_manager,
|
def init_settings(self, ipython_app, kernel_manager, contents_manager,
|
||||||
cluster_manager, session_manager, kernel_spec_manager,
|
cluster_manager, session_manager, kernel_spec_manager,
|
||||||
|
config_manager,
|
||||||
log, base_url, default_url, settings_overrides,
|
log, base_url, default_url, settings_overrides,
|
||||||
jinja_env_options=None):
|
jinja_env_options=None):
|
||||||
|
|
||||||
@ -172,6 +174,7 @@ class NotebookWebApplication(web.Application):
|
|||||||
cluster_manager=cluster_manager,
|
cluster_manager=cluster_manager,
|
||||||
session_manager=session_manager,
|
session_manager=session_manager,
|
||||||
kernel_spec_manager=kernel_spec_manager,
|
kernel_spec_manager=kernel_spec_manager,
|
||||||
|
config_manager=config_manager,
|
||||||
|
|
||||||
# IPython stuff
|
# IPython stuff
|
||||||
nbextensions_path = ipython_app.nbextensions_path,
|
nbextensions_path = ipython_app.nbextensions_path,
|
||||||
@ -607,6 +610,11 @@ class NotebookApp(BaseIPythonApplication):
|
|||||||
help='The cluster manager class to use.'
|
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)
|
kernel_spec_manager = Instance(KernelSpecManager)
|
||||||
|
|
||||||
def _kernel_spec_manager_default(self):
|
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 = kls(parent=self, log=self.log)
|
||||||
self.cluster_manager.update_profiles()
|
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):
|
def init_logging(self):
|
||||||
# This prevents double log messages because tornado use a root logger that
|
# 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
|
# 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.web_app = NotebookWebApplication(
|
||||||
self, self.kernel_manager, self.contents_manager,
|
self, self.kernel_manager, self.contents_manager,
|
||||||
self.cluster_manager, self.session_manager, self.kernel_spec_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.log, self.base_url, self.default_url, self.tornado_settings,
|
||||||
self.jinja_environment_options
|
self.jinja_environment_options
|
||||||
)
|
)
|
||||||
|
@ -11,85 +11,27 @@ from tornado import web
|
|||||||
from IPython.utils.py3compat import PY3
|
from IPython.utils.py3compat import PY3
|
||||||
from ...base.handlers import IPythonHandler, json_errors
|
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):
|
class ConfigHandler(IPythonHandler):
|
||||||
SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH')
|
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
|
@web.authenticated
|
||||||
@json_errors
|
@json_errors
|
||||||
def get(self, section_name):
|
def get(self, section_name):
|
||||||
self.set_header("Content-Type", 'application/json')
|
self.set_header("Content-Type", 'application/json')
|
||||||
filename = self.file_name(section_name)
|
self.finish(json.dumps(self.config_manager.get(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
|
@web.authenticated
|
||||||
@json_errors
|
@json_errors
|
||||||
def put(self, section_name):
|
def put(self, section_name):
|
||||||
self.get_json_body() # Will raise 400 if content is not valid JSON
|
data = self.get_json_body() # Will raise 400 if content is not valid JSON
|
||||||
filename = self.file_name(section_name)
|
self.config_manager.set(section_name, data)
|
||||||
self.ensure_config_dir_exists()
|
|
||||||
with open(filename, 'wb') as f:
|
|
||||||
f.write(self.request.body)
|
|
||||||
self.set_status(204)
|
self.set_status(204)
|
||||||
|
|
||||||
@web.authenticated
|
@web.authenticated
|
||||||
@json_errors
|
@json_errors
|
||||||
def patch(self, section_name):
|
def patch(self, section_name):
|
||||||
filename = self.file_name(section_name)
|
new_data = self.get_json_body()
|
||||||
if os.path.isfile(filename):
|
section = self.config_manager.update(section_name, new_data)
|
||||||
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)
|
|
||||||
|
|
||||||
self.finish(json.dumps(section))
|
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