Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package jupyter-jupyterlab-server for
openSUSE:Factory checked in at 2021-09-22 22:13:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/jupyter-jupyterlab-server (Old)
and /work/SRC/openSUSE:Factory/.jupyter-jupyterlab-server.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "jupyter-jupyterlab-server"
Wed Sep 22 22:13:04 2021 rev:6 rq:920994 version:2.8.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/jupyter-jupyterlab-server/jupyter-jupyterlab-server.changes
2021-08-23 10:08:36.244216017 +0200
+++
/work/SRC/openSUSE:Factory/.jupyter-jupyterlab-server.new.1899/jupyter-jupyterlab-server.changes
2021-09-22 22:13:26.444347143 +0200
@@ -1,0 +2,24 @@
+Fri Sep 17 09:06:02 UTC 2021 - Ben Greiner <[email protected]>
+
+- Update to 2.8.2
+ * Fall back to DEFAULT_LOCALE when translation settings schema is
+ invalid in get_current_locale
+ * Translate settings schema
+- Really remove the patch jupyterlab-server-pr198-openapi014.patch
+
+-------------------------------------------------------------------
+Mon Sep 6 17:27:13 UTC 2021 - Ben Greiner <[email protected]>
+
+- Update to 2.7.2
+ * Do not overwrite capitalization of region names #202
+ * Use Check Links Action #201
+ * Recommend pytest --pyargs jupyterlab_server #203
+- Changlog for release 2.7.1
+ * Fix reset user settings if validation failed #199
+ * support openapi-core 0.14 SpecPath #198
+- Drop jupyterlab-server-pr198-openapi014.patch merged upstream
+ * gh#jupyterlab/jupyterlab_server#198
+- Fix jupyter-jupyterlab-server-rpmlintrc for rpmlint 2 errors
+- All the test exceptions have been resolved upstream
+
+-------------------------------------------------------------------
Old:
----
jupyterlab-server-pr198-openapi014.patch
jupyterlab_server-2.7.0.tar.gz
New:
----
jupyterlab_server-2.8.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ jupyter-jupyterlab-server.spec ++++++
--- /var/tmp/diff_new_pack.VagAaL/_old 2021-09-22 22:13:26.968347579 +0200
+++ /var/tmp/diff_new_pack.VagAaL/_new 2021-09-22 22:13:26.972347582 +0200
@@ -19,15 +19,13 @@
%define skip_python2 1
%define oldpython python
Name: jupyter-jupyterlab-server
-Version: 2.7.0
+Version: 2.8.1
Release: 0
Summary: Server components for JupyterLab and JupyterLab-like
applications
License: BSD-3-Clause
URL: https://github.com/jupyterlab/jupyterlab_server
Source:
https://files.pythonhosted.org/packages/source/j/jupyterlab_server/jupyterlab_server-%{version}.tar.gz
Source100: jupyter-jupyterlab-server-rpmlintrc
-# PATCH-FIX-UPSTREAM jupyterlab-server-pr198-openapi014.patch --
gh#jupyterlab/jupyterlab_server#198
-Patch0: jupyterlab-server-pr198-openapi014.patch
BuildRequires: %{python_module Babel}
BuildRequires: %{python_module Jinja2 >= 2.10}
BuildRequires: %{python_module base >= 3.5}
@@ -101,12 +99,7 @@
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-# we dont have the language packs installed, supposed to be tested here
-donttest+=" or (test_translation_api and (get_locale or backend_locale or
get_installed or get_language) and not (_not_ or bad or fails))"
-# flaky
-donttest+=" or (test_workspaces_api and test_get_non_existant)"
-mv jupyterlab_server/tests/conftest.py ./
-%pytest -ra -k "not (${donttest:4})"
+%pytest --pyargs jupyterlab_server -ra
%files %{python_files}
%license LICENSE
++++++ jupyter-jupyterlab-server-rpmlintrc ++++++
--- /var/tmp/diff_new_pack.VagAaL/_old 2021-09-22 22:13:27.000347605 +0200
+++ /var/tmp/diff_new_pack.VagAaL/_new 2021-09-22 22:13:27.000347605 +0200
@@ -1,4 +1,4 @@
-# This is an importan test file.
+# This is an important test file.
# The tests don't work without it, and other packages' tests depend on these
tests being available
addFilter("backup-file-in-package
.*/jupyterlab_server/tests/schemas/@jupyterlab/shortcuts-extension/package.json.orig")
-addFilter("suse-filelist-forbidden
.*/jupyterlab_server/tests/schemas/@jupyterlab/shortcuts-extension/package.json.orig")
+addFilter("filelist-forbidden
.*/jupyterlab_server/tests/schemas/@jupyterlab/shortcuts-extension/package.json.orig")
++++++ jupyterlab_server-2.7.0.tar.gz -> jupyterlab_server-2.8.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyterlab_server-2.7.0/CHANGELOG.md
new/jupyterlab_server-2.8.1/CHANGELOG.md
--- old/jupyterlab_server-2.7.0/CHANGELOG.md 2021-08-11 16:05:01.000000000
+0200
+++ new/jupyterlab_server-2.8.1/CHANGELOG.md 2021-09-07 20:22:44.000000000
+0200
@@ -6,6 +6,76 @@
<!-- <START NEW CHANGELOG ENTRY> -->
+## 2.8.1
+
+([Full
Changelog](https://github.com/jupyterlab/jupyterlab_server/compare/v2.8.0...680f4fe1c8c7d1d7841e14562720d81a27e6d0ad))
+
+### Bugs fixed
+
+- Fall back to `DEFAULT_LOCALE` when translation settings schema is invalid in
`get_current_locale`
[#207](https://github.com/jupyterlab/jupyterlab_server/pull/207)
([@telamonian](https://github.com/telamonian))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyterlab/jupyterlab_server/graphs/contributors?from=2021-09-07&to=2021-09-07&type=c))
+
+[@telamonian](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Atelamonian+updated%3A2021-09-07..2021-09-07&type=Issues)
+
+<!-- <END NEW CHANGELOG ENTRY> -->
+
+## 2.8.0
+
+([Full
Changelog](https://github.com/jupyterlab/jupyterlab_server/compare/v2.7.2...407a8e997825e76b7f9c8992ee03206c21ea0fa0))
+
+### Enhancements made
+
+- Translate settings schema
[#205](https://github.com/jupyterlab/jupyterlab_server/pull/205)
([@fcollonval](https://github.com/fcollonval))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyterlab/jupyterlab_server/graphs/contributors?from=2021-08-23&to=2021-09-07&type=c))
+
+[@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Afcollonval+updated%3A2021-08-23..2021-09-07&type=Issues)
+
+## 2.7.2
+
+([Full
Changelog](https://github.com/jupyterlab/jupyterlab_server/compare/v2.7.1...1508ff86421f1473ad388ac2d384bf986e326862))
+
+### Bugs fixed
+
+- Do not overwrite capitalization of region names
[#202](https://github.com/jupyterlab/jupyterlab_server/pull/202)
([@krassowski](https://github.com/krassowski))
+
+### Maintenance and upkeep improvements
+
+- Use Check Links Action
[#201](https://github.com/jupyterlab/jupyterlab_server/pull/201)
([@blink1073](https://github.com/blink1073))
+
+### Documentation improvements
+
+- Recommend `pytest --pyargs jupyterlab_server`
[#203](https://github.com/jupyterlab/jupyterlab_server/pull/203)
([@krassowski](https://github.com/krassowski))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyterlab/jupyterlab_server/graphs/contributors?from=2021-08-17&to=2021-08-23&type=c))
+
+[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Ablink1073+updated%3A2021-08-17..2021-08-23&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Acodecov-commenter+updated%3A2021-08-17..2021-08-23&type=Issues)
|
[@krassowski](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Akrassowski+updated%3A2021-08-17..2021-08-23&type=Issues)
+
+## 2.7.1
+
+([Full
Changelog](https://github.com/jupyterlab/jupyterlab_server/compare/v2.7.0...4c5f9c84fa4c1be2267712d2a5f28fe82bdf9047))
+
+### Bugs fixed
+
+- Fix reset user settings if validation failed
[#199](https://github.com/jupyterlab/jupyterlab_server/pull/199)
([@fcollonval](https://github.com/fcollonval))
+
+### Maintenance and upkeep improvements
+
+- TST: support openapi-core 0.14 SpecPath
[#198](https://github.com/jupyterlab/jupyterlab_server/pull/198)
([@bnavigator](https://github.com/bnavigator))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyterlab/jupyterlab_server/graphs/contributors?from=2021-08-11&to=2021-08-17&type=c))
+
+[@blink1073](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Ablink1073+updated%3A2021-08-11..2021-08-17&type=Issues)
|
[@bnavigator](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Abnavigator+updated%3A2021-08-11..2021-08-17&type=Issues)
|
[@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Afcollonval+updated%3A2021-08-11..2021-08-17&type=Issues)
|
[@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Awelcome+updated%3A2021-08-11..2021-08-17&type=Issues)
+
## 2.7.0
([Full
Changelog](https://github.com/jupyterlab/jupyterlab_server/compare/v2.6.2...919186b026f8c86f2f14c11318776e272a9dd629))
@@ -20,8 +90,6 @@
[@fcollonval](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Afcollonval+updated%3A2021-08-03..2021-08-11&type=Issues)
|
[@welcome](https://github.com/search?q=repo%3Ajupyterlab%2Fjupyterlab_server+involves%3Awelcome+updated%3A2021-08-03..2021-08-11&type=Issues)
-<!-- <END NEW CHANGELOG ENTRY> -->
-
## 2.6.2
([Full
Changelog](https://github.com/jupyterlab/jupyterlab_server/compare/v2.6.1...1ac80fc439a8150de11bc470d370693cf5389781))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyterlab_server-2.7.0/CONTRIBUTING.md
new/jupyterlab_server-2.8.1/CONTRIBUTING.md
--- old/jupyterlab_server-2.7.0/CONTRIBUTING.md 2021-08-11 16:05:01.000000000
+0200
+++ new/jupyterlab_server-2.8.1/CONTRIBUTING.md 2021-09-07 20:22:44.000000000
+0200
@@ -16,5 +16,5 @@
git clone https://github.com/jupyterlab/jupyterlab_server.git
cd jupyterlab_server
pip install -e .[test] # install test dependencies
-pytest
+pytest --pyargs jupyterlab_server
```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyterlab_server-2.7.0/PKG-INFO
new/jupyterlab_server-2.8.1/PKG-INFO
--- old/jupyterlab_server-2.7.0/PKG-INFO 2021-08-11 16:05:38.722334000
+0200
+++ new/jupyterlab_server-2.8.1/PKG-INFO 2021-09-07 20:23:32.172667000
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: jupyterlab_server
-Version: 2.7.0
+Version: 2.8.1
Summary: A set of server components for JupyterLab and JupyterLab like
applications .
Home-page: https://jupyter.org
Author: Jupyter Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/_version.py
new/jupyterlab_server-2.8.1/jupyterlab_server/_version.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/_version.py 2021-08-11
16:05:24.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/_version.py 2021-09-07
20:23:14.000000000 +0200
@@ -4,7 +4,7 @@
"""
import re
-__version__ = '2.7.0'
+__version__ = '2.8.1'
# Build up version_info tuple for backwards compatibility
pattern = r'(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/handlers.py
new/jupyterlab_server-2.8.1/jupyterlab_server/handlers.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/handlers.py 2021-08-11
16:05:01.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/handlers.py 2021-09-07
20:22:44.000000000 +0200
@@ -201,6 +201,19 @@
setting_path = ujoin(extension_app.settings_url, '(?P<schema_name>.+)')
handlers.append((setting_path, SettingsHandler, settings_config))
+ # Handle translations.
+ ## Translations requires settings as the locale source of truth is
stored in it
+ if extension_app.translations_api_url:
+ # Handle requests for the list of language packs available.
+ # Make slash optional.
+ translations_path = ujoin(extension_app.translations_api_url, '?')
+ handlers.append((translations_path, TranslationsHandler,
settings_config))
+
+ # Handle requests for an individual language pack.
+ translations_lang_path = ujoin(
+ extension_app.translations_api_url, '(?P<locale>.*)')
+ handlers.append((translations_lang_path, TranslationsHandler,
settings_config))
+
# Handle saved workspaces.
if extension_app.workspaces_dir:
@@ -279,18 +292,6 @@
}
))
- # Handle translations.
- if extension_app.translations_api_url:
- # Handle requests for the list of language packs available.
- # Make slash optional.
- translations_path = ujoin(extension_app.translations_api_url, '?')
- handlers.append((translations_path, TranslationsHandler,
{'lab_config': extension_app}))
-
- # Handle requests for an individual language pack.
- translations_lang_path = ujoin(
- extension_app.translations_api_url, '(?P<locale>.*)')
- handlers.append((translations_lang_path, TranslationsHandler,
{'lab_config': extension_app}))
-
# Let the lab handler act as the fallthrough option instead of a 404.
fallthrough_url = ujoin(extension_app.app_url, r'.*')
handlers.append((fallthrough_url, NotFoundHandler))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/settings_handler.py
new/jupyterlab_server-2.8.1/jupyterlab_server/settings_handler.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/settings_handler.py
2021-08-11 16:05:01.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/settings_handler.py
2021-09-07 20:22:44.000000000 +0200
@@ -3,355 +3,47 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import json
-import os
-from glob import glob
-import json5
-from jsonschema import Draft4Validator as Validator
from jsonschema import ValidationError
-from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin,
ExtensionHandlerMixin
-from jupyter_server.services.config.manager import ConfigManager,
recursive_update
+from jupyter_server.extension.handler import (
+ ExtensionHandlerJinjaMixin,
+ ExtensionHandlerMixin,
+)
from tornado import web
-from .server import APIHandler, tz
+from .settings_utils import SchemaHandler, get_settings, save_settings
+from .translation_utils import DEFAULT_LOCALE, translator
-# The JupyterLab settings file extension.
-SETTINGS_EXTENSION = '.jupyterlab-settings'
-
-def _get_schema(schemas_dir, schema_name, overrides, labextensions_path):
- """Returns a dict containing a parsed and validated JSON schema."""
- notfound_error = 'Schema not found: %s'
- parse_error = 'Failed parsing schema (%s): %s'
- validation_error = 'Failed validating schema (%s): %s'
-
- path = None
-
- # Look for the setting in all of the labextension paths first
- # Use the first one
- if labextensions_path is not None:
- ext_name, _, plugin_name = schema_name.partition(':')
- for ext_path in labextensions_path:
- target = os.path.join(ext_path, ext_name, 'schemas', ext_name,
plugin_name + '.json')
- if os.path.exists(target):
- schemas_dir = os.path.join(ext_path, ext_name, 'schemas')
- path = target
- break
-
- # Fall back on the default location
- if path is None:
- path = _path(schemas_dir, schema_name)
-
- if not os.path.exists(path):
- raise web.HTTPError(404, notfound_error % path)
-
- with open(path, encoding='utf-8') as fid:
- # Attempt to load the schema file.
- try:
- schema = json.load(fid)
- except Exception as e:
- name = schema_name
- raise web.HTTPError(500, parse_error % (name, str(e)))
-
- schema = _override(schema_name, schema, overrides)
-
- # Validate the schema.
- try:
- Validator.check_schema(schema)
- except Exception as e:
- name = schema_name
- raise web.HTTPError(500, validation_error % (name, str(e)))
-
- version = _get_version(schemas_dir, schema_name)
-
- return schema, version
-
-
-def _get_user_settings(settings_dir, schema_name, schema):
- """
- Returns a dictionary containing the raw user settings, the parsed user
- settings, a validation warning for a schema, and file times.
- """
- path = _path(settings_dir, schema_name, False, SETTINGS_EXTENSION)
- raw = '{}'
- settings = {}
- warning = None
- validation_warning = 'Failed validating settings (%s): %s'
- parse_error = 'Failed loading settings (%s): %s'
- last_modified = None
- created = None
-
- if os.path.exists(path):
- stat = os.stat(path)
- last_modified = tz.utcfromtimestamp(stat.st_mtime).isoformat()
- created = tz.utcfromtimestamp(stat.st_ctime).isoformat()
- with open(path, encoding='utf-8') as fid:
- try: # to load and parse the settings file.
- raw = fid.read() or raw
- settings = json5.loads(raw)
- except Exception as e:
- raise web.HTTPError(500, parse_error % (schema_name, str(e)))
-
- # Validate the parsed data against the schema.
- if len(settings):
- validator = Validator(schema)
- try:
- validator.validate(settings)
- except ValidationError as e:
- warning = validation_warning % (schema_name, str(e))
- raw = '{}'
-
- return dict(
- raw=raw,
- settings=settings,
- warning=warning,
- last_modified=last_modified,
- created=created
- )
-
-
-def _get_version(schemas_dir, schema_name):
- """Returns the package version for a given schema or 'N/A' if not found."""
-
- path = _path(schemas_dir, schema_name)
- package_path = os.path.join(os.path.split(path)[0], 'package.json.orig')
-
- try: # to load and parse the package.json.orig file.
- with open(package_path, encoding='utf-8') as fid:
- package = json.load(fid)
- return package['version']
- except Exception:
- return 'N/A'
-
-
-def _list_settings(schemas_dir, settings_dir, overrides, extension='.json',
labextensions_path=None):
- """
- Returns a tuple containing:
- - the list of plugins, schemas, and their settings,
- respecting any defaults that may have been overridden.
- - the list of warnings that were generated when
- validating the user overrides against the schemas.
- """
-
- settings = {}
- federated_settings = {}
- warnings = []
-
- if not os.path.exists(schemas_dir):
- warnings = ['Settings directory does not exist at %s' % schemas_dir]
- return ([], warnings)
-
- schema_pattern = schemas_dir + '/**/*' + extension
- schema_paths = [path for path in glob(schema_pattern, recursive=True)]
- schema_paths.sort()
-
- for schema_path in schema_paths:
- # Generate the schema_name used to request individual settings.
- rel_path = os.path.relpath(schema_path, schemas_dir)
- rel_schema_dir, schema_base = os.path.split(rel_path)
- id = schema_name = ':'.join([
- rel_schema_dir,
- schema_base[:-len(extension)] # Remove file extension.
- ]).replace('\\', '/') # Normalize slashes.
- schema, version = _get_schema(schemas_dir, schema_name, overrides,
None)
- user_settings = _get_user_settings(settings_dir, schema_name, schema)
-
- if user_settings["warning"]:
- warnings.append(user_settings.pop('warning'))
-
- # Add the plugin to the list of settings.
- settings[id] = dict(
- id=id,
- schema=schema,
- version=version,
- **user_settings
+class SettingsHandler(ExtensionHandlerMixin, ExtensionHandlerJinjaMixin,
SchemaHandler):
+ def initialize(
+ self,
+ name,
+ app_settings_dir,
+ schemas_dir,
+ settings_dir,
+ labextensions_path,
+ **kwargs
+ ):
+ SchemaHandler.initialize(
+ self, app_settings_dir, schemas_dir, settings_dir,
labextensions_path
)
-
- if labextensions_path is not None:
- schema_paths = []
- for ext_dir in labextensions_path:
- schema_pattern = ext_dir + '/**/schemas/**/*' + extension
- schema_paths.extend([path for path in glob(schema_pattern,
recursive=True)])
-
- schema_paths.sort()
-
- for schema_path in schema_paths:
- schema_path = schema_path.replace(os.sep, '/')
-
- base_dir, rel_path = schema_path.split('schemas/')
-
- # Generate the schema_name used to request individual settings.
- rel_schema_dir, schema_base = os.path.split(rel_path)
- id = schema_name = ':'.join([
- rel_schema_dir,
- schema_base[:-len(extension)] # Remove file extension.
- ]).replace('\\', '/') # Normalize slashes.
-
- # bail if we've already handled the highest federated setting
- if id in federated_settings:
- continue
-
- schema, version = _get_schema(schemas_dir, schema_name, overrides,
labextensions_path=labextensions_path)
- user_settings = _get_user_settings(settings_dir, schema_name,
schema)
-
- if user_settings["warning"]:
- warnings.append(user_settings.pop('warning'))
-
- # Add the plugin to the list of settings.
- federated_settings[id] = dict(
- id=id,
- schema=schema,
- version=version,
- **user_settings
- )
-
- settings.update(federated_settings)
- settings_list = [settings[key] for key in sorted(settings.keys(),
reverse=True)]
-
- return (settings_list, warnings)
-
-
-def _override(schema_name, schema, overrides):
- """Override default values in the schema if necessary."""
- if schema_name in overrides:
- defaults = overrides[schema_name]
- for key in defaults:
- if key in schema['properties']:
- new_defaults = schema['properties'][key]['default']
- # If values for defaults are dicts do a recursive update
- if isinstance(new_defaults, dict):
- recursive_update(new_defaults, defaults[key])
- else:
- new_defaults = defaults[key]
-
- schema['properties'][key]['default'] = new_defaults
- else:
- schema['properties'][key] = dict(default=defaults[key])
-
- return schema
-
-
-def _path(root_dir, schema_name, make_dirs=False, extension='.json'):
- """
- Returns the local file system path for a schema name in the given root
- directory. This function can be used to filed user overrides in addition to
- schema files. If the `make_dirs` flag is set to `True` it will create the
- parent directory for the calculated path if it does not exist.
- """
-
- parent_dir = root_dir
- notfound_error = 'Settings not found (%s)'
- write_error = 'Failed writing settings (%s): %s'
-
- try: # to parse path, e.g. @jupyterlab/apputils-extension:themes.
- package_dir, plugin = schema_name.split(':')
- parent_dir = os.path.join(root_dir, package_dir)
- path = os.path.join(parent_dir, plugin + extension)
- except Exception:
- raise web.HTTPError(404, notfound_error % schema_name)
-
- if make_dirs and not os.path.exists(parent_dir):
- try:
- os.makedirs(parent_dir)
- except Exception as e:
- raise web.HTTPError(500, write_error % (schema_name, str(e)))
-
- return path
-
-
-def _get_overrides(app_settings_dir):
- """Get overrides settings from `app_settings_dir`."""
- 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')
-
- if os.path.exists(overrides_path):
- with open(overrides_path, encoding='utf-8') as fid:
- try:
- overrides = json5.load(fid)
- 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'))
-
- return overrides, error
-
-
-def get_settings(app_settings_dir, schemas_dir, settings_dir, schema_name="",
overrides=None, labextensions_path=None):
- """
- Get setttings.
-
- Parameters
- ----------
- app_settings_dir:
- Path to applications settings.
- schemas_dir: str
- Path to schemas.
- settings_dir:
- Path to settings.
- schema_name str, optional
- Schema name. Default is "".
- overrides: dict, optional
- Settings overrides. If not provided, the overrides will be loaded
- from the `app_settings_dir`. Default is None.
- labextensions_path: list, optional
- List of paths to federated labextensions containing their own schema
files.
-
- Returns
- -------
- tuple
- The first item is a dictionary with a list of setting if no
`schema_name`
- was provided, otherwise it is a dictionary with id, raw, scheme,
settings
- and version keys. The second item is a list of warnings. Warnings will
- either be a list of i) strings with the warning messages or ii) `None`.
- """
- result = {}
- warnings = []
-
- if overrides is None:
- overrides, _error = _get_overrides(app_settings_dir)
-
- if schema_name:
- schema, version = _get_schema(schemas_dir, schema_name, overrides,
labextensions_path)
- user_settings = _get_user_settings(settings_dir, schema_name, schema)
- warnings = [user_settings.pop('warning')]
- result = {
- "id": schema_name,
- "schema": schema,
- "version": version,
- **user_settings
- }
- else:
- settings_list, warnings = _list_settings(schemas_dir, settings_dir,
overrides, labextensions_path=labextensions_path)
- result = {
- "settings": settings_list,
- }
-
- return result, warnings
-
-
-class SettingsHandler(ExtensionHandlerMixin, ExtensionHandlerJinjaMixin,
APIHandler):
-
- def initialize(self, name, app_settings_dir, schemas_dir, settings_dir,
labextensions_path, **kwargs):
- super().initialize(name)
- self.overrides, error = _get_overrides(app_settings_dir)
- self.app_settings_dir = app_settings_dir
- self.schemas_dir = schemas_dir
- self.settings_dir = settings_dir
- self.labextensions_path = labextensions_path
-
- if error:
- overrides_warning = 'Failed loading overrides: %s'
- self.log.warn(overrides_warning % str(error))
+ ExtensionHandlerMixin.initialize(self, name)
@web.authenticated
def get(self, schema_name=""):
"""Get setting(s)"""
+ # Need to be update here as translator locale is not change when a new
locale is put
+ # from frontend
+ try:
+ locale = self.get_current_locale()
+ except web.HTTPError as e:
+ # fallback in case of missing (404) or misshapen (500) translation
schema
+ locale = DEFAULT_LOCALE
+ 'Failed loading or validating translation settings schema'
+
+ translator.set_locale(locale)
+
result, warnings = get_settings(
self.app_settings_dir,
self.schemas_dir,
@@ -359,6 +51,7 @@
labextensions_path=self.labextensions_path,
schema_name=schema_name,
overrides=self.overrides,
+ translator=translator.translate_schema
)
# Print all warnings.
@@ -384,24 +77,20 @@
raw_payload = self.request.body.strip().decode('utf-8')
try:
- raw_settings = json.loads(raw_payload)['raw']
- payload = json5.loads(raw_settings)
+ raw_settings = json.loads(raw_payload)["raw"]
+ save_settings(
+ schemas_dir,
+ settings_dir,
+ schema_name,
+ raw_settings,
+ overrides,
+ self.labextensions_path,
+ )
except json.decoder.JSONDecodeError as e:
raise web.HTTPError(400, invalid_json_error % str(e))
except (KeyError, TypeError) as e:
raise web.HTTPError(400, invalid_payload_format_error)
-
- # Validate the data against the schema.
- schema, _ = _get_schema(schemas_dir, schema_name, overrides,
labextensions_path=self.labextensions_path)
- validator = Validator(schema)
- try:
- validator.validate(payload)
except ValidationError as e:
raise web.HTTPError(400, validation_error % str(e))
- # Write the raw data (comments included) to a file.
- path = _path(settings_dir, schema_name, True, SETTINGS_EXTENSION)
- with open(path, 'w', encoding='utf-8') as fid:
- fid.write(raw_settings)
-
self.set_status(204)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/settings_utils.py
new/jupyterlab_server-2.8.1/jupyterlab_server/settings_utils.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/settings_utils.py
1970-01-01 01:00:00.000000000 +0100
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/settings_utils.py
2021-09-07 20:22:44.000000000 +0200
@@ -0,0 +1,456 @@
+"""Frontend config storage helpers."""
+
+# Copyright (c) Jupyter Development Team.
+# Distributed under the terms of the Modified BSD License.
+from glob import glob
+import json
+import json5
+from jsonschema import Draft4Validator as Validator, ValidationError
+from jupyter_server.services.config.manager import ConfigManager,
recursive_update
+import os
+from tornado import web
+
+from .server import APIHandler, tz
+from .translation_utils import DEFAULT_LOCALE, L10N_SCHEMA_NAME,
is_valid_locale
+
+# The JupyterLab settings file extension.
+SETTINGS_EXTENSION = '.jupyterlab-settings'
+
+
+def _get_schema(schemas_dir, schema_name, overrides, labextensions_path):
+ """Returns a dict containing a parsed and validated JSON schema."""
+ notfound_error = 'Schema not found: %s'
+ parse_error = 'Failed parsing schema (%s): %s'
+ validation_error = 'Failed validating schema (%s): %s'
+
+ path = None
+
+ # Look for the setting in all of the labextension paths first
+ # Use the first one
+ if labextensions_path is not None:
+ ext_name, _, plugin_name = schema_name.partition(':')
+ for ext_path in labextensions_path:
+ target = os.path.join(ext_path, ext_name, 'schemas', ext_name,
plugin_name + '.json')
+ if os.path.exists(target):
+ schemas_dir = os.path.join(ext_path, ext_name, 'schemas')
+ path = target
+ break
+
+ # Fall back on the default location
+ if path is None:
+ path = _path(schemas_dir, schema_name)
+
+ if not os.path.exists(path):
+ raise web.HTTPError(404, notfound_error % path)
+
+ with open(path, encoding='utf-8') as fid:
+ # Attempt to load the schema file.
+ try:
+ schema = json.load(fid)
+ except Exception as e:
+ name = schema_name
+ raise web.HTTPError(500, parse_error % (name, str(e)))
+
+ schema = _override(schema_name, schema, overrides)
+
+ # Validate the schema.
+ try:
+ Validator.check_schema(schema)
+ except Exception as e:
+ name = schema_name
+ raise web.HTTPError(500, validation_error % (name, str(e)))
+
+ version = _get_version(schemas_dir, schema_name)
+
+ return schema, version
+
+
+def _get_user_settings(settings_dir, schema_name, schema):
+ """
+ Returns a dictionary containing the raw user settings, the parsed user
+ settings, a validation warning for a schema, and file times.
+ """
+ path = _path(settings_dir, schema_name, False, SETTINGS_EXTENSION)
+ raw = '{}'
+ settings = {}
+ warning = None
+ validation_warning = 'Failed validating settings (%s): %s'
+ parse_error = 'Failed loading settings (%s): %s'
+ last_modified = None
+ created = None
+
+ if os.path.exists(path):
+ stat = os.stat(path)
+ last_modified = tz.utcfromtimestamp(stat.st_mtime).isoformat()
+ created = tz.utcfromtimestamp(stat.st_ctime).isoformat()
+ with open(path, encoding='utf-8') as fid:
+ try: # to load and parse the settings file.
+ raw = fid.read() or raw
+ settings = json5.loads(raw)
+ except Exception as e:
+ raise web.HTTPError(500, parse_error % (schema_name, str(e)))
+
+ # Validate the parsed data against the schema.
+ if len(settings):
+ validator = Validator(schema)
+ try:
+ validator.validate(settings)
+ except ValidationError as e:
+ warning = validation_warning % (schema_name, str(e))
+ raw = '{}'
+ settings = {}
+
+ return dict(
+ raw=raw,
+ settings=settings,
+ warning=warning,
+ last_modified=last_modified,
+ created=created
+ )
+
+
+def _get_version(schemas_dir, schema_name):
+ """Returns the package version for a given schema or 'N/A' if not found."""
+
+ path = _path(schemas_dir, schema_name)
+ package_path = os.path.join(os.path.split(path)[0], 'package.json.orig')
+
+ try: # to load and parse the package.json.orig file.
+ with open(package_path, encoding='utf-8') as fid:
+ package = json.load(fid)
+ return package['version']
+ except Exception:
+ return 'N/A'
+
+
+def _list_settings(
+ schemas_dir,
+ settings_dir,
+ overrides,
+ extension=".json",
+ labextensions_path=None,
+ translator=None,
+):
+ """
+ Returns a tuple containing:
+ - the list of plugins, schemas, and their settings,
+ respecting any defaults that may have been overridden.
+ - the list of warnings that were generated when
+ validating the user overrides against the schemas.
+ """
+
+ settings = {}
+ federated_settings = {}
+ warnings = []
+
+ if not os.path.exists(schemas_dir):
+ warnings = ['Settings directory does not exist at %s' % schemas_dir]
+ return ([], warnings)
+
+ schema_pattern = schemas_dir + '/**/*' + extension
+ schema_paths = [path for path in glob(schema_pattern, recursive=True)]
+ schema_paths.sort()
+
+ for schema_path in schema_paths:
+ # Generate the schema_name used to request individual settings.
+ rel_path = os.path.relpath(schema_path, schemas_dir)
+ rel_schema_dir, schema_base = os.path.split(rel_path)
+ id = schema_name = ':'.join([
+ rel_schema_dir,
+ schema_base[:-len(extension)] # Remove file extension.
+ ]).replace('\\', '/') # Normalize slashes.
+ schema, version = _get_schema(schemas_dir, schema_name, overrides,
None)
+ if translator is not None:
+ schema = translator(schema)
+ user_settings = _get_user_settings(settings_dir, schema_name, schema)
+
+ if user_settings["warning"]:
+ warnings.append(user_settings.pop('warning'))
+
+ # Add the plugin to the list of settings.
+ settings[id] = dict(
+ id=id,
+ schema=schema,
+ version=version,
+ **user_settings
+ )
+
+ if labextensions_path is not None:
+ schema_paths = []
+ for ext_dir in labextensions_path:
+ schema_pattern = ext_dir + '/**/schemas/**/*' + extension
+ schema_paths.extend([path for path in glob(schema_pattern,
recursive=True)])
+
+ schema_paths.sort()
+
+ for schema_path in schema_paths:
+ schema_path = schema_path.replace(os.sep, '/')
+
+ base_dir, rel_path = schema_path.split('schemas/')
+
+ # Generate the schema_name used to request individual settings.
+ rel_schema_dir, schema_base = os.path.split(rel_path)
+ id = schema_name = ':'.join([
+ rel_schema_dir,
+ schema_base[:-len(extension)] # Remove file extension.
+ ]).replace('\\', '/') # Normalize slashes.
+
+ # bail if we've already handled the highest federated setting
+ if id in federated_settings:
+ continue
+
+ schema, version = _get_schema(schemas_dir, schema_name, overrides,
labextensions_path=labextensions_path)
+ user_settings = _get_user_settings(settings_dir, schema_name,
schema)
+
+ if user_settings["warning"]:
+ warnings.append(user_settings.pop('warning'))
+
+ # Add the plugin to the list of settings.
+ federated_settings[id] = dict(
+ id=id,
+ schema=schema,
+ version=version,
+ **user_settings
+ )
+
+ settings.update(federated_settings)
+ settings_list = [settings[key] for key in sorted(settings.keys(),
reverse=True)]
+
+ return (settings_list, warnings)
+
+
+def _override(schema_name, schema, overrides):
+ """Override default values in the schema if necessary."""
+ if schema_name in overrides:
+ defaults = overrides[schema_name]
+ for key in defaults:
+ if key in schema['properties']:
+ new_defaults = schema['properties'][key]['default']
+ # If values for defaults are dicts do a recursive update
+ if isinstance(new_defaults, dict):
+ recursive_update(new_defaults, defaults[key])
+ else:
+ new_defaults = defaults[key]
+
+ schema['properties'][key]['default'] = new_defaults
+ else:
+ schema['properties'][key] = dict(default=defaults[key])
+
+ return schema
+
+
+def _path(root_dir, schema_name, make_dirs=False, extension='.json'):
+ """
+ Returns the local file system path for a schema name in the given root
+ directory. This function can be used to filed user overrides in addition to
+ schema files. If the `make_dirs` flag is set to `True` it will create the
+ parent directory for the calculated path if it does not exist.
+ """
+
+ parent_dir = root_dir
+ notfound_error = 'Settings not found (%s)'
+ write_error = 'Failed writing settings (%s): %s'
+
+ try: # to parse path, e.g. @jupyterlab/apputils-extension:themes.
+ package_dir, plugin = schema_name.split(':')
+ parent_dir = os.path.join(root_dir, package_dir)
+ path = os.path.join(parent_dir, plugin + extension)
+ except Exception:
+ raise web.HTTPError(404, notfound_error % schema_name)
+
+ if make_dirs and not os.path.exists(parent_dir):
+ try:
+ os.makedirs(parent_dir)
+ except Exception as e:
+ raise web.HTTPError(500, write_error % (schema_name, str(e)))
+
+ return path
+
+
+def _get_overrides(app_settings_dir):
+ """Get overrides settings from `app_settings_dir`."""
+ 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')
+
+ if os.path.exists(overrides_path):
+ with open(overrides_path, encoding='utf-8') as fid:
+ try:
+ overrides = json5.load(fid)
+ 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'))
+
+ return overrides, error
+
+
+def get_settings(
+ app_settings_dir,
+ schemas_dir,
+ settings_dir,
+ schema_name="",
+ overrides=None,
+ labextensions_path=None,
+ translator=None,
+):
+ """
+ Get settings.
+
+ Parameters
+ ----------
+ app_settings_dir:
+ Path to applications settings.
+ schemas_dir: str
+ Path to schemas.
+ settings_dir:
+ Path to settings.
+ schema_name str, optional
+ Schema name. Default is "".
+ overrides: dict, optional
+ Settings overrides. If not provided, the overrides will be loaded
+ from the `app_settings_dir`. Default is None.
+ labextensions_path: list, optional
+ List of paths to federated labextensions containing their own schema
files.
+ translator: Callable[[Dict], Dict] or None, optional
+ Translate a schema. It requires the schema dictionary and returns its
translation
+
+ Returns
+ -------
+ tuple
+ The first item is a dictionary with a list of setting if no
`schema_name`
+ was provided, otherwise it is a dictionary with id, raw, scheme,
settings
+ and version keys. The second item is a list of warnings. Warnings will
+ either be a list of i) strings with the warning messages or ii) `None`.
+ """
+ result = {}
+ warnings = []
+
+ if overrides is None:
+ overrides, _error = _get_overrides(app_settings_dir)
+
+ if schema_name:
+ schema, version = _get_schema(
+ schemas_dir, schema_name, overrides, labextensions_path
+ )
+ if translator is not None:
+ schema = translator(schema)
+ user_settings = _get_user_settings(settings_dir, schema_name, schema)
+ warnings = [user_settings.pop('warning')]
+ result = {
+ "id": schema_name,
+ "schema": schema,
+ "version": version,
+ **user_settings
+ }
+ else:
+ settings_list, warnings = _list_settings(
+ schemas_dir,
+ settings_dir,
+ overrides,
+ labextensions_path=labextensions_path,
+ translator=translator,
+ )
+ result = {
+ "settings": settings_list,
+ }
+
+ return result, warnings
+
+
+def save_settings(
+ schemas_dir,
+ settings_dir,
+ schema_name,
+ raw_settings,
+ overrides,
+ labextensions_path=None,
+):
+ """
+ Save ``raw_settings`` settings for ``schema_name``.
+
+ Parameters
+ ----------
+ schemas_dir: str
+ Path to schemas.
+ settings_dir: str
+ Path to settings.
+ schema_name str
+ Schema name.
+ raw_settings: str
+ Raw serialized settings dictionary
+ overrides: dict
+ Settings overrides.
+ labextensions_path: list, optional
+ List of paths to federated labextensions containing their own schema
files.
+ """
+ payload = json5.loads(raw_settings)
+
+ # Validate the data against the schema.
+ schema, _ = _get_schema(
+ schemas_dir, schema_name, overrides,
labextensions_path=labextensions_path
+ )
+ validator = Validator(schema)
+ validator.validate(payload)
+
+ # Write the raw data (comments included) to a file.
+ path = _path(settings_dir, schema_name, True, SETTINGS_EXTENSION)
+ with open(path, "w", encoding="utf-8") as fid:
+ fid.write(raw_settings)
+
+
+class SchemaHandler(APIHandler):
+ """Base handler for handler requiring access to settings."""
+
+ def initialize(
+ self, app_settings_dir, schemas_dir, settings_dir, labextensions_path,
**kwargs
+ ):
+ super().initialize(**kwargs)
+ self.overrides, error = _get_overrides(app_settings_dir)
+ self.app_settings_dir = app_settings_dir
+ self.schemas_dir = schemas_dir
+ self.settings_dir = settings_dir
+ self.labextensions_path = labextensions_path
+
+ if error:
+ overrides_warning = "Failed loading overrides: %s"
+ self.log.warn(overrides_warning % str(error))
+
+ def get_current_locale(self):
+ """
+ Get the current locale as specified in the translation-extension
settings.
+
+ Returns
+ -------
+ str
+ The current locale string.
+
+ Notes
+ -----
+ If the locale setting is not available or not valid, it will default
to jupyterlab_server.translation_utils.DEFAULT_LOCALE.
+ """
+ try:
+ settings, _ = get_settings(
+ self.app_settings_dir,
+ self.schemas_dir,
+ self.settings_dir,
+ schema_name=L10N_SCHEMA_NAME,
+ overrides=self.overrides,
+ labextensions_path=self.labextensions_path,
+ )
+ except web.HTTPError as e:
+ schema_warning = "Missing or misshappen translation settings
schema:\n%s"
+ self.log.warn(schema_warning % str(e))
+
+ settings = {}
+
+ current_locale = settings.get("settings", {}).get("locale",
DEFAULT_LOCALE)
+ if not is_valid_locale(current_locale):
+ current_locale = DEFAULT_LOCALE
+
+ return current_locale
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/tests/test_translation_api.py
new/jupyterlab_server-2.8.1/jupyterlab_server/tests/test_translation_api.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/tests/test_translation_api.py
2021-08-11 16:05:01.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/tests/test_translation_api.py
2021-09-07 20:22:44.000000000 +0200
@@ -219,6 +219,7 @@
assert get_display_name("en", "fr") == "Anglais"
assert get_display_name("es", "en") == "Spanish"
assert get_display_name("fr", "en") == "French"
+ assert get_display_name("pl_pl", "en") == "Polish (Poland)"
def test_get_display_name_invalid():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/tests/utils.py
new/jupyterlab_server-2.8.1/jupyterlab_server/tests/utils.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/tests/utils.py
2021-08-11 16:05:01.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/tests/utils.py
2021-09-07 20:22:44.000000000 +0200
@@ -44,7 +44,7 @@
# work around lack of support for path parameters which can contain slashes
# https://github.com/OAI/OpenAPI-Specification/issues/892
url = None
- for path in spec.paths:
+ for path in spec['paths']:
if url:
continue
has_arg = '{' in path
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/translation_utils.py
new/jupyterlab_server-2.8.1/jupyterlab_server/translation_utils.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/translation_utils.py
2021-08-11 16:05:01.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/translation_utils.py
2021-09-07 20:22:44.000000000 +0200
@@ -7,9 +7,11 @@
import importlib
import json
import os
-import subprocess
+import re
import sys
import traceback
+from functools import lru_cache
+from typing import Dict, Pattern
import babel
import entrypoints
@@ -23,6 +25,44 @@
DEFAULT_LOCALE = "en"
LOCALE_DIR = "locale"
LC_MESSAGES_DIR = "LC_MESSAGES"
+DEFAULT_DOMAIN = "jupyterlab"
+L10N_SCHEMA_NAME = "@jupyterlab/translation-extension:plugin"
+
+_default_schema_context = "schema"
+_default_settings_context = "settings"
+_lab_i18n_config = "jupyter.lab.internationalization"
+
+# mapping of schema translatable string selectors to translation context
+DEFAULT_SCHEMA_SELECTORS = {
+ "properties/.*/title": _default_settings_context,
+ "properties/.*/description": _default_settings_context,
+ "definitions/.*/properties/.*/title": _default_settings_context,
+ "definitions/.*/properties/.*/description": _default_settings_context,
+ "title": _default_schema_context,
+ "description": _default_schema_context,
+ # JupyterLab-specific
+ "jupyter\.lab\.setting-icon-label": _default_settings_context,
+ "jupyter\.lab\.menus/.*/label": "menu",
+ "jupyter\.lab\.toolbars/.*/label": "toolbar",
+}
+
+
+@lru_cache()
+def _get_default_schema_selectors() -> Dict[Pattern, str]:
+ return {
+ re.compile("^/" + pattern + "$"): context
+ for pattern, context in DEFAULT_SCHEMA_SELECTORS.items()
+ }
+
+
+def _prepare_schema_patterns(schema: dict) -> Dict[Pattern, str]:
+ return {
+ **_get_default_schema_selectors(),
+ **{
+ re.compile("^/" + selector + "$"): _default_schema_context
+ for selector in schema.get(_lab_i18n_config, {}).get("selectors",
[])
+ },
+ }
# --- Private process helpers
@@ -164,7 +204,10 @@
display_locale if is_valid_locale(display_locale) else DEFAULT_LOCALE
)
loc = babel.Locale.parse(locale)
- return loc.get_display_name(display_locale).capitalize()
+ display_name = loc.get_display_name(display_locale)
+ if display_name:
+ display_name = display_name[0].upper() + display_name[1:]
+ return display_name
def merge_locale_data(language_pack_locale_data, package_locale_data):
@@ -428,7 +471,7 @@
"""
return gettext.dngettext(self._domain, msgid, msgid_plural, n)
- def pgettext(self, msgctxt: str, singular: str) -> str:
+ def pgettext(self, msgctxt: str, msgid: str) -> str:
"""
Translate a singular string with context.
@@ -503,7 +546,7 @@
str
The translated string.
"""
- return self.ngettext(msgid, plural, n)
+ return self.ngettext(msgid, msgid_plural, n)
def _p(self, msgctxt: str, msgid: str) -> str:
"""
@@ -523,7 +566,7 @@
"""
return self.pgettext(msgctxt, msgid)
- def _np(self, msgctxt: str, msgid: str, msgid_plular: str, n: str) -> str:
+ def _np(self, msgctxt: str, msgid: str, msgid_plural: str, n: str) -> str:
"""
Shorthand for npgettext.
@@ -543,13 +586,14 @@
str
The translated string.
"""
- return self.npgettext(msgctxt, msgid, msgid_plular, n)
+ return self.npgettext(msgctxt, msgid, msgid_plural, n)
class translator:
"""
Translations manager.
"""
+
_TRANSLATORS = {}
_LOCALE = DEFAULT_LOCALE
@@ -566,6 +610,22 @@
for key in ["LANGUAGE", "LANG"]:
os.environ[key] = f"{locale}.UTF-8"
+ @staticmethod
+ def normalize_domain(domain: str) -> str:
+ """Normalize a domain name.
+
+ Parameters
+ ----------
+ domain: str
+ Domain to normalize
+
+ Returns
+ -------
+ str
+ Normalized domain
+ """
+ return domain.replace("-", "_")
+
@classmethod
def set_locale(cls, locale: str):
"""
@@ -576,6 +636,10 @@
locale: str
The language name to use.
"""
+ if locale == cls._LOCALE:
+ # Nothing to do bail early
+ return
+
if is_valid_locale(locale):
cls._LOCALE = locale
translator._update_env(locale)
@@ -599,14 +663,81 @@
Translator
A translator instance bound to the domain.
"""
- if domain in cls._TRANSLATORS:
- trans = cls._TRANSLATORS[domain]
+ norm_domain = translator.normalize_domain(domain)
+ if norm_domain in cls._TRANSLATORS:
+ trans = cls._TRANSLATORS[norm_domain]
else:
- trans = TranslationBundle(domain, cls._LOCALE)
- cls._TRANSLATORS[domain] = trans
+ trans = TranslationBundle(norm_domain, cls._LOCALE)
+ cls._TRANSLATORS[norm_domain] = trans
return trans
+ @staticmethod
+ def _translate_schema_strings(
+ translations,
+ schema: dict,
+ prefix: str = "",
+ to_translate: Dict[Pattern, str] = None,
+ ) -> None:
+ """Translate a schema in-place."""
+ if to_translate is None:
+ to_translate = _prepare_schema_patterns(schema)
+
+ for key, value in schema.items():
+ path = prefix + "/" + key
+
+ if isinstance(value, str):
+ matched = False
+ for pattern, context in to_translate.items():
+ if pattern.fullmatch(path):
+ matched = True
+ break
+ if matched:
+ schema[key] = translations.pgettext(context, value)
+ elif isinstance(value, dict):
+ translator._translate_schema_strings(
+ translations,
+ value,
+ prefix=path,
+ to_translate=to_translate,
+ )
+ elif isinstance(value, list):
+ for i, element in enumerate(value):
+ if not isinstance(element, dict):
+ continue
+ translator._translate_schema_strings(
+ translations,
+ element,
+ prefix=path + "[" + str(i) + "]",
+ to_translate=to_translate,
+ )
+
+ @staticmethod
+ def translate_schema(schema: Dict) -> Dict:
+ """Translate a schema.
+
+ Parameters
+ ----------
+ schema: dict
+ The schema to be translated
+
+ Returns
+ -------
+ Dict
+ The translated schema
+ """
+ if translator._LOCALE == DEFAULT_LOCALE:
+ return schema
+
+ translations = translator.load(
+ schema.get(_lab_i18n_config, {}).get("domain", DEFAULT_DOMAIN)
+ )
+
+ new_schema = schema.copy()
+ translator._translate_schema_strings(translations, schema.copy())
+
+ return new_schema
+
if __name__ == "__main__":
_main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server/translations_handler.py
new/jupyterlab_server-2.8.1/jupyterlab_server/translations_handler.py
--- old/jupyterlab_server-2.7.0/jupyterlab_server/translations_handler.py
2021-08-11 16:05:01.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server/translations_handler.py
2021-09-07 20:22:44.000000000 +0200
@@ -11,49 +11,11 @@
import tornado
from tornado import gen
-from .server import APIHandler
-from .settings_handler import get_settings
+from .settings_utils import SchemaHandler
from .translation_utils import get_language_pack, get_language_packs,
is_valid_locale, translator
-SCHEMA_NAME = '@jupyterlab/translation-extension:plugin'
-
-
-def get_current_locale(config):
- """
- Get the current locale for given `config`.
-
- Parameters
- ----------
- config: LabConfig
- The config.
-
- Returns
- -------
- str
- The current locale string.
-
- Notes
- -----
- If the locale setting is not valid, it will default to "en".
- """
- settings, _warnings = get_settings(
- config.app_settings_dir,
- config.schemas_dir,
- config.user_settings_dir,
- schema_name=SCHEMA_NAME,
- )
- current_locale = settings.get("settings", {}).get("locale", "en")
- if not is_valid_locale(current_locale):
- current_locale = "en"
-
- return current_locale
-
-
-class TranslationsHandler(APIHandler):
-
- def initialize(self, lab_config):
- self.lab_config = lab_config
+class TranslationsHandler(SchemaHandler):
@gen.coroutine
@tornado.web.authenticated
@@ -71,7 +33,8 @@
try:
if locale == "":
data, message = get_language_packs(
- display_locale=get_current_locale(self.lab_config))
+ display_locale=self.get_current_locale()
+ )
else:
data, message = get_language_pack(locale)
if data == {} and message == "":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server.egg-info/PKG-INFO
new/jupyterlab_server-2.8.1/jupyterlab_server.egg-info/PKG-INFO
--- old/jupyterlab_server-2.7.0/jupyterlab_server.egg-info/PKG-INFO
2021-08-11 16:05:38.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server.egg-info/PKG-INFO
2021-09-07 20:23:32.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: jupyterlab-server
-Version: 2.7.0
+Version: 2.8.1
Summary: A set of server components for JupyterLab and JupyterLab like
applications .
Home-page: https://jupyter.org
Author: Jupyter Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server.egg-info/SOURCES.txt
new/jupyterlab_server-2.8.1/jupyterlab_server.egg-info/SOURCES.txt
--- old/jupyterlab_server-2.7.0/jupyterlab_server.egg-info/SOURCES.txt
2021-08-11 16:05:38.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server.egg-info/SOURCES.txt
2021-09-07 20:23:32.000000000 +0200
@@ -34,6 +34,7 @@
jupyterlab_server/rest-api.yml
jupyterlab_server/server.py
jupyterlab_server/settings_handler.py
+jupyterlab_server/settings_utils.py
jupyterlab_server/themes_handler.py
jupyterlab_server/translation_utils.py
jupyterlab_server/translations_handler.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyterlab_server-2.7.0/jupyterlab_server.egg-info/requires.txt
new/jupyterlab_server-2.8.1/jupyterlab_server.egg-info/requires.txt
--- old/jupyterlab_server-2.7.0/jupyterlab_server.egg-info/requires.txt
2021-08-11 16:05:38.000000000 +0200
+++ new/jupyterlab_server-2.8.1/jupyterlab_server.egg-info/requires.txt
2021-09-07 20:23:32.000000000 +0200
@@ -13,7 +13,7 @@
pytest>=5.3.2
pytest-cov
jupyter_server[test]
-openapi_core~=0.13.8
+openapi_core~=0.14.0
pytest-console-scripts
strict-rfc3339
ruamel.yaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyterlab_server-2.7.0/pyproject.toml
new/jupyterlab_server-2.8.1/pyproject.toml
--- old/jupyterlab_server-2.7.0/pyproject.toml 2021-08-11 16:05:24.000000000
+0200
+++ new/jupyterlab_server-2.8.1/pyproject.toml 2021-09-07 20:23:14.000000000
+0200
@@ -2,12 +2,15 @@
requires = ["jupyter_packaging~=0.9,<2", "jupyter_server"]
build-backend = "setuptools.build_meta"
+[tool.jupyter-releaser]
+skip = ["check-links"]
+
[tool.check-manifest]
ignore = ["tbump.toml", ".*", "*.yml", "docs/source/api/app-config.rst",
"docs/source/changelog.md"]
ignore-bad-ideas = ["jupyterlab_server/tests/translations/**/*.mo"]
[tool.tbump.version]
-current = "2.7.0"
+current = "2.8.1"
regex = '''
(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
((?P<channel>a|b|rc|.dev)(?P<release>\d+))?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyterlab_server-2.7.0/setup.cfg
new/jupyterlab_server-2.8.1/setup.cfg
--- old/jupyterlab_server-2.7.0/setup.cfg 2021-08-11 16:05:38.722334000
+0200
+++ new/jupyterlab_server-2.8.1/setup.cfg 2021-09-07 20:23:32.172667000
+0200
@@ -37,7 +37,7 @@
jupyter_server~=1.4
[options.extras_require]
-test = codecov; ipykernel; pytest>=5.3.2; pytest-cov; jupyter_server[test];
openapi_core~=0.13.8; pytest-console-scripts; strict-rfc3339; ruamel.yaml; wheel
+test = codecov; ipykernel; pytest>=5.3.2; pytest-cov; jupyter_server[test];
openapi_core~=0.14.0; pytest-console-scripts; strict-rfc3339; ruamel.yaml; wheel
[options.packages.find]
exclude = ['docs*']