Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add overrides.d for settings defaults #224

Merged
merged 1 commit into from
Dec 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions jupyterlab_server/settings_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,26 +266,50 @@ def _path(root_dir, schema_name, make_dirs=False, extension='.json'):

return path


def _get_overrides(app_settings_dir):
"""Get overrides settings from `app_settings_dir`."""
"""Get overrides settings from `app_settings_dir`.

The ordering of paths is:
- {app_settings_dir}/overrides.d/*.{json,json5} (many, namespaced by package)
- {app_settings_dir}/overrides.{json,json5} (singleton, owned by the user)
"""
overrides, error = {}, ""
overrides_path = os.path.join(app_settings_dir, 'overrides.json')

if not os.path.exists(overrides_path):
overrides_path = os.path.join(app_settings_dir, 'overrides.json5')
overrides_d = os.path.join(app_settings_dir, 'overrides.d')

# find (and sort) the conf.d overrides files
all_override_paths = sorted([
*(glob(os.path.join(overrides_d, '*.json'))),
*(glob(os.path.join(overrides_d, '*.json5'))),
])

all_override_paths += [
os.path.join(app_settings_dir, 'overrides.json'),
os.path.join(app_settings_dir, 'overrides.json5')
]

for overrides_path in all_override_paths:
if not os.path.exists(overrides_path):
continue

if os.path.exists(overrides_path):
with open(overrides_path, encoding='utf-8') as fid:
try:
overrides = json5.load(fid)
if overrides_path.endswith('.json5'):
path_overrides = json5.load(fid)
else:
path_overrides = json.load(fid)
for plugin_id, config in path_overrides.items():
recursive_update(overrides.setdefault(plugin_id, {}), config)
print(overrides_path, overrides)
except Exception as e:
error = e

# Allow `default_settings_overrides.json` files in <jupyter_config>/labconfig dirs
# to allow layering of defaults
cm = ConfigManager(config_dir_name="labconfig")
recursive_update(overrides, cm.get('default_setting_overrides'))

for plugin_id, config in cm.get('default_setting_overrides').items():
recursive_update(overrides.setdefault(plugin_id, {}), config)

return overrides, error

Expand Down
25 changes: 24 additions & 1 deletion jupyterlab_server/tests/test_settings_api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Test the Settings service API.
"""
from pathlib import Path
import json

import pytest
import json
import json5
import tornado

Expand All @@ -28,6 +29,28 @@ async def test_get_settings_overrides_dicts(jp_fetch, labserverapp):
assert len(schema['properties']['codeCellConfig']['default']) == 15


@pytest.mark.parametrize('ext', ['json', 'json5'])
async def test_get_settings_overrides_d_dicts(jp_fetch, labserverapp, ext):
# Check that values that are dictionaries in overrides.d/*.json are
# merged with the schema.
id = '@jupyterlab/apputils-extension:themes'
overrides_d = Path(labserverapp.app_settings_dir) / "overrides.d"
overrides_d.mkdir(exist_ok=True, parents=True)
for i in range(10):
text = json.dumps({id: {'codeCellConfig': {'cursorBlinkRate': 530 + i}}})
if ext == 'json5':
text += '\n// a comment'
(overrides_d / f"foo-{i}.{ext}").write_text(text, encoding='utf-8')
r = await jp_fetch('lab', 'api', 'settings', id)
validate_request(r)
res = r.body.decode()
data = json.loads(res)
assert data['id'] == id
schema = data['schema']
# Check that the last overrides.d/*.json file is respected.
assert schema['properties']['codeCellConfig']['default']['cursorBlinkRate'] == 539


async def test_get_settings(jp_fetch, labserverapp):
id = '@jupyterlab/apputils-extension:themes'
r = await jp_fetch('lab', 'api', 'settings', id)
Expand Down