Commit d093e10e authored by Piergiorgio Pancino's avatar Piergiorgio Pancino Committed by Benoit Formet
Browse files

config.static.Config: exception management

- option to not raise exception ported from method to an instance attribute
  (allows starting and reloading the page without exceptions)
- Improved exception handling and messages for user
parent aed40f57
Pipeline #26359 passed with stages
in 55 minutes and 3 seconds
......@@ -89,9 +89,9 @@ class WebConfig(object):
def get_config(self):
with self.__lock:
cfg = static.get_config()
cfg = static.get_config(raise_yaml_exc=False)
if self.__new_config:
cfg.reload(raise_yaml_exc=False)
cfg.reload()
self.__new_config = False
return cfg
......@@ -541,7 +541,7 @@ def get_item_config(name):
@web_app.route("/config/reload")
def reload_config():
cfg = __config.get_config()
cfg.reload(raise_yaml_exc=False)
cfg.reload()
event.send(server.__name__, "config_changed")
return flask.json.dumps(
dict(message="Configuration fully reloaded!", type="success")
......
......@@ -148,7 +148,7 @@ def _replace_node_with_ref(node):
node[key] = _replace_list_node_with_ref(value)
def get_config(base_path="", timeout=3.):
def get_config(base_path="", timeout=3., raise_yaml_exc=True):
"""
Return configuration from bliss configuration server
......@@ -175,13 +175,15 @@ def get_config(base_path="", timeout=3.):
Args:
base_path (str): base path to config
timeout (float): response timeout (seconds)
raise_yaml_exc (bool): if False will not raise exceptions related
to yaml parsing and config nodes creation
Returns:
Config: the configuration object
"""
global CONFIG
if CONFIG is None:
CONFIG = Config(base_path, timeout)
CONFIG = Config(base_path, timeout, raise_yaml_exc=raise_yaml_exc)
return CONFIG
......@@ -492,7 +494,7 @@ class Node(dict):
)
class InvalidConfig(Exception):
class InvalidConfig(RuntimeError):
pass
......@@ -509,7 +511,8 @@ class Config:
USER_TAG_KEY = "user_tag"
def __init__(self, base_path, timeout=3, connection=None):
def __init__(self, base_path, timeout=3, connection=None, raise_yaml_exc=True):
self.raise_yaml_exc = raise_yaml_exc
self._base_path = base_path
self._connection = connection or client.get_default_connection()
self.reload(timeout=timeout)
......@@ -569,23 +572,34 @@ class Config:
yaml = YAML(pure=True)
yaml.allow_duplicate_keys = True
d = yaml.load(file_content)
except ruamel.yaml.scanner.ScannerError as exp:
except (
ruamel.yaml.scanner.ScannerError,
ruamel.yaml.parser.ParserError,
) as exp:
exp.note = "Error in YAML parsing:\n"
exp.note += "----------------\n"
exp.note += f"{file_content}\n"
exp.note += "----------------\n"
exp.note += "Hint: You can check your configuration with an on-line YAML validator like http://www.yamllint.com/ \n\n"
exp.problem_mark.name = path
if raise_yaml_exc:
if self.raise_yaml_exc:
raise exp
else:
print("INVALID 1")
raise InvalidConfig("Error in YAML parsing", path)
# from ruamel.yaml.parser import ParserError
except ruamel.yaml.error.MarkedYAMLError as exp:
if exp.problem_mark is not None:
exp.problem_mark.name = path
raise
if self.raise_yaml_exc:
raise exp
else:
raise InvalidConfig("Error in YAML parsing", path)
except ruamel.yaml.error.MarkedYAMLError as exp:
if exp.problem_mark is not None:
exp.problem_mark.name = path
if self.raise_yaml_exc:
raise exp
else:
raise InvalidConfig("Error in YAML parsing", path)
is_init_file = False
if file_name.startswith("__init__"):
......@@ -600,12 +614,19 @@ class Config:
parents["__children__"] = []
# do not accept a list in case of __init__ file
if isinstance(d, MutableSequence):
raise TypeError("List are not allowed in *%s* file" % path)
_msg = "List are not allowed in *%s* file" % path
if self.raise_yaml_exc:
raise TypeError(_msg)
else:
raise InvalidConfig(_msg, path)
try:
self._parse(d, parents)
except TypeError:
_msg = "Parsing error1 on %s in '%s'" % (self._connection, path)
raise RuntimeError(_msg)
except (TypeError, AttributeError):
_msg = ("Error while parsing '{path}'",)
if self.raise_yaml_exc:
raise RuntimeError(_msg)
else:
raise InvalidConfig(_msg, path)
if not fs_key:
self._root_node = parents
......@@ -619,46 +640,39 @@ class Config:
local_parent = Node(self, fs_node, path)
try:
self._parse(item, local_parent)
except TypeError:
_msg = "Parsing error2 on %s in '%s'" % (
self._connection,
path,
)
if raise_yaml_exc:
except (TypeError, AttributeError):
_msg = f"Error while parsing a list on '{path}'"
if self.raise_yaml_exc:
raise RuntimeError(_msg)
else:
raise InvalidConfig(_msg, path)
try:
self._create_index(local_parent)
except ValueError:
if raise_yaml_exc:
except ValueError as exc:
if self.raise_yaml_exc:
raise
else:
print("INVALID 2", item)
raise InvalidConfig("INVALID 2", path)
# Duplicated key in config
raise InvalidConfig(" ".join(exc.args), path)
else:
parents.append(local_parent)
else:
parents = Node(self, fs_node, path)
try:
self._parse(d, parents)
except TypeError:
_msg = "Parsing error3 on %s in '%s'" % (
self._connection,
path,
)
if raise_yaml_exc:
except (TypeError, AttributeError):
_msg = f"Error while parsing '{path}'"
if self.raise_yaml_exc:
raise RuntimeError(_msg)
else:
raise InvalidConfig(_msg, path)
try:
self._create_index(parents)
except ValueError:
if raise_yaml_exc:
except ValueError as exc:
if self.raise_yaml_exc:
raise
else:
print("INVALID 3")
raise InvalidConfig("INVALID 3", path)
raise InvalidConfig(*exc.args, path)
if isinstance(fs_node, MutableSequence):
continue
......@@ -921,7 +935,7 @@ class Config:
def _parse(self, d, parent):
if d is None:
raise RuntimeError("Error parsing %r" % parent)
raise TypeError("Error parsing %r" % parent)
else:
for key, value in d.items():
if isinstance(value, MutableMapping):
......
......@@ -87,7 +87,7 @@ def test_empty_yml(beacon, beacon_directory):
with pytest.raises(RuntimeError) as exc:
beacon.reload()
assert "filename" in str(exc.value)
assert "toto.yml" in str(exc.value)
finally:
os.unlink(new_file)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment