mirror of
https://github.com/jupyter/notebook.git
synced 2025-03-19 13:20:36 +08:00
allow default json files in a .d directory, original PR: ipython/traitlets#452
This commit is contained in:
parent
ae011a1797
commit
89b32e4412
@ -1,6 +1,6 @@
|
||||
from notebook.auth import passwd
|
||||
from getpass import getpass
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
from jupyter_core.paths import jupyter_config_dir
|
||||
import argparse
|
||||
import sys
|
||||
|
@ -5,10 +5,10 @@ import os
|
||||
|
||||
from ..extensions import BaseExtensionApp, _get_config_dir, GREEN_ENABLED, RED_DISABLED
|
||||
from .._version import __version__
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
|
||||
from jupyter_core.paths import jupyter_config_path
|
||||
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from traitlets.utils.importstring import import_item
|
||||
from traitlets import Bool
|
||||
|
||||
|
@ -15,10 +15,10 @@ except ImportError:
|
||||
from ipython_genutils.tempdir import TemporaryDirectory
|
||||
from ipython_genutils import py3compat
|
||||
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from traitlets.tests.utils import check_help_all_output
|
||||
|
||||
import notebook.nbextensions as nbextensions
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
from ..bundlerextensions import (_get_config_dir, enable_bundler_python,
|
||||
disable_bundler_python)
|
||||
|
||||
|
103
notebook/manager.py
Normal file
103
notebook/manager.py
Normal file
@ -0,0 +1,103 @@
|
||||
"""Manager to read and modify config data in JSON files.
|
||||
"""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
import errno
|
||||
import glob
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
|
||||
from six import PY3
|
||||
from traitlets.config import LoggingConfigurable
|
||||
from traitlets.traitlets import Unicode, Bool
|
||||
|
||||
|
||||
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 BaseJSONConfigManager(LoggingConfigurable):
|
||||
"""General JSON config manager
|
||||
|
||||
Deals with persisting/storing config in a json file with optionally
|
||||
default values in a {section_name}.d directory.
|
||||
"""
|
||||
|
||||
config_dir = Unicode('.')
|
||||
read_directory = Bool(True)
|
||||
|
||||
def ensure_config_dir_exists(self):
|
||||
try:
|
||||
os.makedirs(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 directory(self, section_name):
|
||||
return os.path.join(self.config_dir, section_name+'.d')
|
||||
|
||||
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.
|
||||
"""
|
||||
paths = [self.file_name(section_name)]
|
||||
if self.read_directory:
|
||||
pattern = os.path.join(self.directory(section_name), '*.json')
|
||||
# These json files should be processed first so that the
|
||||
# {section_name}.json take precedence.
|
||||
# The idea behind this is that installing a Python package may
|
||||
# put a json file somewhere in the a .d directory, while the
|
||||
# .json file is probably a user configuration.
|
||||
paths = sorted(glob.glob(pattern)) + paths
|
||||
data = {}
|
||||
for path in paths:
|
||||
if os.path.isfile(path):
|
||||
with io.open(path, encoding='utf-8') as f:
|
||||
recursive_update(data, json.load(f))
|
||||
return data
|
||||
|
||||
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, indent=2)
|
||||
|
||||
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
|
@ -29,7 +29,7 @@ from ipython_genutils.py3compat import string_types, cast_unicode_py2
|
||||
from ipython_genutils.tempdir import TemporaryDirectory
|
||||
from ._version import __version__
|
||||
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
from traitlets.utils.importstring import import_item
|
||||
|
||||
DEPRECATED_ARGUMENT = object()
|
||||
|
@ -16,7 +16,7 @@ from .extensions import (
|
||||
)
|
||||
from traitlets import Bool
|
||||
from traitlets.utils.importstring import import_item
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
import os.path
|
||||
|
||||
from traitlets.config.manager import BaseJSONConfigManager, recursive_update
|
||||
from notebook.manager import BaseJSONConfigManager, recursive_update
|
||||
from jupyter_core.paths import jupyter_config_dir, jupyter_config_path
|
||||
from traitlets import Unicode, Instance, List, observe, default
|
||||
from traitlets.config import LoggingConfigurable
|
||||
|
34
notebook/tests/test_manager.py
Normal file
34
notebook/tests/test_manager.py
Normal file
@ -0,0 +1,34 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
|
||||
|
||||
def test_json(tmpdir):
|
||||
tmpdir = str(tmpdir) # we're ok with a regular string path
|
||||
with open(os.path.join(tmpdir, 'foo.json'), 'w') as f:
|
||||
json.dump(dict(a=1), f)
|
||||
# also make a foo.d/ directory with multiple json files
|
||||
os.makedirs(os.path.join(tmpdir, 'foo.d'))
|
||||
with open(os.path.join(tmpdir, 'foo.d', 'a.json'), 'w') as f:
|
||||
json.dump(dict(a=2, b=1), f)
|
||||
with open(os.path.join(tmpdir, 'foo.d', 'b.json'), 'w') as f:
|
||||
json.dump(dict(a=3, b=2, c=3), f)
|
||||
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False)
|
||||
data = manager.get('foo')
|
||||
assert 'a' in data
|
||||
assert 'b' not in data
|
||||
assert 'c' not in data
|
||||
assert data['a'] == 1
|
||||
|
||||
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=True)
|
||||
data = manager.get('foo')
|
||||
assert 'a' in data
|
||||
assert 'b' in data
|
||||
assert 'c' in data
|
||||
# files should be read in order foo.d/a.json foo.d/b.json foo.json
|
||||
assert data['a'] == 1
|
||||
assert data['b'] == 2
|
||||
assert data['c'] == 3
|
||||
|
||||
|
@ -30,7 +30,7 @@ from notebook.nbextensions import (install_nbextension, check_nbextension,
|
||||
validate_nbextension, validate_nbextension_python
|
||||
)
|
||||
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
|
||||
|
||||
def touch(file_name, mtime=None):
|
||||
|
@ -10,7 +10,7 @@ except ImportError:
|
||||
from ipython_genutils.tempdir import TemporaryDirectory
|
||||
from ipython_genutils import py3compat
|
||||
|
||||
from traitlets.config.manager import BaseJSONConfigManager
|
||||
from notebook.manager import BaseJSONConfigManager
|
||||
from traitlets.tests.utils import check_help_all_output
|
||||
from jupyter_core import paths
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user