Skip to content

Commit e0fc91b

Browse files
authored
add overrides.d for settings defaults (#224)
1 parent 5f763c6 commit e0fc91b

File tree

2 files changed

+56
-9
lines changed

2 files changed

+56
-9
lines changed

jupyterlab_server/settings_utils.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -266,26 +266,50 @@ def _path(root_dir, schema_name, make_dirs=False, extension='.json'):
266266

267267
return path
268268

269-
270269
def _get_overrides(app_settings_dir):
271-
"""Get overrides settings from `app_settings_dir`."""
270+
"""Get overrides settings from `app_settings_dir`.
271+
272+
The ordering of paths is:
273+
- {app_settings_dir}/overrides.d/*.{json,json5} (many, namespaced by package)
274+
- {app_settings_dir}/overrides.{json,json5} (singleton, owned by the user)
275+
"""
272276
overrides, error = {}, ""
273-
overrides_path = os.path.join(app_settings_dir, 'overrides.json')
274277

275-
if not os.path.exists(overrides_path):
276-
overrides_path = os.path.join(app_settings_dir, 'overrides.json5')
278+
overrides_d = os.path.join(app_settings_dir, 'overrides.d')
279+
280+
# find (and sort) the conf.d overrides files
281+
all_override_paths = sorted([
282+
*(glob(os.path.join(overrides_d, '*.json'))),
283+
*(glob(os.path.join(overrides_d, '*.json5'))),
284+
])
285+
286+
all_override_paths += [
287+
os.path.join(app_settings_dir, 'overrides.json'),
288+
os.path.join(app_settings_dir, 'overrides.json5')
289+
]
290+
291+
for overrides_path in all_override_paths:
292+
if not os.path.exists(overrides_path):
293+
continue
277294

278-
if os.path.exists(overrides_path):
279295
with open(overrides_path, encoding='utf-8') as fid:
280296
try:
281-
overrides = json5.load(fid)
297+
if overrides_path.endswith('.json5'):
298+
path_overrides = json5.load(fid)
299+
else:
300+
path_overrides = json.load(fid)
301+
for plugin_id, config in path_overrides.items():
302+
recursive_update(overrides.setdefault(plugin_id, {}), config)
303+
print(overrides_path, overrides)
282304
except Exception as e:
283305
error = e
284306

285307
# Allow `default_settings_overrides.json` files in <jupyter_config>/labconfig dirs
286308
# to allow layering of defaults
287309
cm = ConfigManager(config_dir_name="labconfig")
288-
recursive_update(overrides, cm.get('default_setting_overrides'))
310+
311+
for plugin_id, config in cm.get('default_setting_overrides').items():
312+
recursive_update(overrides.setdefault(plugin_id, {}), config)
289313

290314
return overrides, error
291315

jupyterlab_server/tests/test_settings_api.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Test the Settings service API.
22
"""
3+
from pathlib import Path
4+
import json
35

46
import pytest
5-
import json
67
import json5
78
import tornado
89

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

3031

32+
@pytest.mark.parametrize('ext', ['json', 'json5'])
33+
async def test_get_settings_overrides_d_dicts(jp_fetch, labserverapp, ext):
34+
# Check that values that are dictionaries in overrides.d/*.json are
35+
# merged with the schema.
36+
id = '@jupyterlab/apputils-extension:themes'
37+
overrides_d = Path(labserverapp.app_settings_dir) / "overrides.d"
38+
overrides_d.mkdir(exist_ok=True, parents=True)
39+
for i in range(10):
40+
text = json.dumps({id: {'codeCellConfig': {'cursorBlinkRate': 530 + i}}})
41+
if ext == 'json5':
42+
text += '\n// a comment'
43+
(overrides_d / f"foo-{i}.{ext}").write_text(text, encoding='utf-8')
44+
r = await jp_fetch('lab', 'api', 'settings', id)
45+
validate_request(r)
46+
res = r.body.decode()
47+
data = json.loads(res)
48+
assert data['id'] == id
49+
schema = data['schema']
50+
# Check that the last overrides.d/*.json file is respected.
51+
assert schema['properties']['codeCellConfig']['default']['cursorBlinkRate'] == 539
52+
53+
3154
async def test_get_settings(jp_fetch, labserverapp):
3255
id = '@jupyterlab/apputils-extension:themes'
3356
r = await jp_fetch('lab', 'api', 'settings', id)

0 commit comments

Comments
 (0)