You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/jupyterlab_server/settings_handler.py

261 lines
8.4 KiB

"""Tornado handlers for frontend config storage."""
# 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 ValidationError
from jsonschema import Draft4Validator as Validator
from tornado import web
from .server import APIHandler, json_errors
# The JupyterLab settings file extension.
SETTINGS_EXTENSION = '.jupyterlab-settings'
def _get_schema(schemas_dir, schema_name, overrides):
"""Returns a dict containing a parsed and validated JSON schema."""
path = _path(schemas_dir, schema_name)
notfound_error = 'Schema not found: %s'
parse_error = 'Failed parsing schema (%s): %s'
validation_error = 'Failed validating schema (%s): %s'
if not os.path.exists(path):
raise web.HTTPError(404, notfound_error % path)
with open(path) 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)))
return schema
def _get_settings(settings_dir, schema_name, schema):
"""
Returns a tuple containing the raw user settings, the parsed user
settings, and a validation warning for a schema.
"""
path = _path(settings_dir, schema_name, False, SETTINGS_EXTENSION)
raw = '{}'
settings = dict()
warning = ''
validation_warning = 'Failed validating settings (%s): %s'
parse_error = 'Failed loading settings (%s): %s'
if os.path.exists(path):
with open(path) 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 (raw, settings, warning)
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) as fid:
package = json.load(fid)
return package['version']
except Exception:
return 'N/A'
def _list_settings(schemas_dir, settings_dir, overrides, extension='.json'):
"""
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_list = []
warnings = []
if not os.path.exists(schemas_dir):
return (settings_list, 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 = _get_schema(schemas_dir, schema_name, overrides)
raw, settings, warning = _get_settings(
settings_dir, schema_name, schema)
version = _get_version(schemas_dir, schema_name)
if warning:
warnings.append(warning)
# Add the plugin to the list of settings.
settings_list.append(dict(
id=id,
raw=raw,
schema=schema,
settings=settings,
version=version
))
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']:
schema['properties'][key]['default'] = defaults[key]
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
class SettingsHandler(APIHandler):
def initialize(self, app_settings_dir, schemas_dir, settings_dir):
self.overrides = dict()
self.schemas_dir = schemas_dir
self.settings_dir = settings_dir
overrides_path = os.path.join(app_settings_dir, 'overrides.json')
overrides_warning = 'Failed loading overrides: %s'
if os.path.exists(overrides_path):
with open(overrides_path) as fid:
try:
self.overrides = json.load(fid)
except Exception as e:
self.log.warn(overrides_warning % str(e))
@web.authenticated
def get(self, schema_name=''):
overrides = self.overrides
schemas_dir = self.schemas_dir
settings_dir = self.settings_dir
if not schema_name:
settings_list, warnings = _list_settings(
schemas_dir, settings_dir, overrides)
if warnings:
self.log.warn('\n'.join(warnings))
return self.finish(json.dumps(dict(settings=settings_list)))
schema = _get_schema(schemas_dir, schema_name, overrides)
raw, settings, warning = _get_settings(
settings_dir, schema_name, schema)
version = _get_version(schemas_dir, schema_name)
if warning:
self.log.warn(warning)
self.finish(json.dumps(dict(
id=schema_name,
raw=raw,
schema=schema,
settings=settings,
version=version
)))
@web.authenticated
def put(self, schema_name):
overrides = self.overrides
schemas_dir = self.schemas_dir
settings_dir = self.settings_dir
settings_error = 'No current settings directory'
validation_error = 'Failed validating input: %s'
if not settings_dir:
raise web.HTTPError(500, settings_error)
raw = self.request.body.strip().decode(u'utf-8')
# Validate the data against the schema.
schema = _get_schema(schemas_dir, schema_name, overrides)
validator = Validator(schema)
try:
validator.validate(json5.loads(raw))
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') as fid:
fid.write(raw)
self.set_status(204)