PyLg/pylg/settings.py

163 lines
5.1 KiB
Python
Raw Normal View History

2019-07-31 20:08:05 +02:00
"""Handlers for PyLg settings."""
from typing import Optional
import os
import yaml
_USER_FILE_NAME = "pylg_settings.yml"
_PYLG_FILE_NAME = "settings.yml"
_BOOL_OPTIONS = set([
"pylg_enable",
"default_exception_warning",
"default_exception_tb_file",
"default_exception_tb_stderr",
"default_exception_exit",
"trace_time",
"trace_filename",
"trace_lineno",
"trace_function",
"class_name_resolution",
"trace_message",
"message_wrap",
"message_mark_truncation",
"trace_self",
"collapse_lists",
"collapse_dicts",
"default_trace_args",
"default_trace_rv",
"default_trace_rv_type",
])
_STRING_OPTIONS = set([
"pylg_file",
"time_format",
])
_POS_INT_OPTIONS = set([
"filename_column_width",
"function_column_width",
])
_NONNEG_OPTIONS = set([
"lineno_width",
"message_width",
])
def load(user_settings_path: Optional[str] = None) -> dict:
"""Load PyLg settings from file.
If a user provides a settings file, it will be used. Otherwise, PyLg's
default settings will be read in.
"""
# -------------------------------------------------------------------------
# Load the default settings.
# -------------------------------------------------------------------------
2017-03-06 00:15:39 +01:00
2019-07-31 20:08:05 +02:00
default_settings_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)), _PYLG_FILE_NAME
)
2017-03-06 00:15:39 +01:00
2019-07-31 20:08:05 +02:00
with open(default_settings_path, 'r') as settings_file:
default_settings = yaml.full_load(settings_file)
2017-03-06 00:15:39 +01:00
2019-07-31 20:08:05 +02:00
# -------------------------------------------------------------------------
# Load the user settings.
# -------------------------------------------------------------------------
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
user_settings = {}
if user_settings_path is not None:
with open(user_settings_path, 'r') as settings_file:
user_settings = yaml.full_load(settings_file)
2017-03-17 00:17:34 +01:00
2019-07-31 20:08:05 +02:00
# -------------------------------------------------------------------------
# Merge the two settings preferring user values over defaults.
# -------------------------------------------------------------------------
2017-03-17 00:17:34 +01:00
2019-07-31 20:08:05 +02:00
settings = {**default_settings, **user_settings}
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
# -------------------------------------------------------------------------
# Verify the input.
# -------------------------------------------------------------------------
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
for option in settings.keys():
source_file = (user_settings_path
if option in user_settings
else default_settings_path)
option_type = type(settings[option]).__name__
option_value = settings[option]
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
if option in _BOOL_OPTIONS:
if not _pylg_check_bool(option_value):
raise ImportError(
"Invalid type for {} in {} - should be bool, is type {}"
.format(option, source_file, option_type)
)
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
elif option in _STRING_OPTIONS:
if not _pylg_check_string(option_value):
raise ImportError(
"Invalid type for {} in {} - should be str, is type {}"
.format(option, source_file, option_type)
)
elif option in _POS_INT_OPTIONS:
if not _pylg_check_pos_int(option_value):
raise ImportError(
"Invalid type/value for {} in {} - "
"should be positive int, is {}"
.format(option, source_file, option_value)
)
elif option in _NONNEG_OPTIONS:
if not _pylg_check_nonneg_int(option_value):
raise ImportError(
"Invalid type/value for {} in {} - "
"should be non-negative int, is {}"
.format(option, source_file, option_value)
)
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
else:
raise ImportError("Unrecognised option in {}: {}"
.format(source_file, option))
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
# -------------------------------------------------------------------------
# Some final value processing.
# -------------------------------------------------------------------------
if settings["message_width"] == 0:
settings["message_width"] = float("inf")
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
return settings
2017-03-09 01:10:28 +01:00
# -----------------------------------------------------------------------------
2019-07-31 20:08:05 +02:00
# Utility functions for sanity checking user settings.
2017-03-09 01:10:28 +01:00
# -----------------------------------------------------------------------------
2019-07-31 20:08:05 +02:00
def _pylg_check_bool(value) -> bool:
return isinstance(value, bool)
2017-03-06 00:15:39 +01:00
2019-07-31 20:08:05 +02:00
def _pylg_check_string(value) -> bool:
return isinstance(value, str)
2017-03-06 00:15:39 +01:00
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
def _pylg_check_int(value) -> bool:
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
# -------------------------------------------------------------------------
# We check for bool as well as bools are an instance of int, but we don't
# want to let that go through.
# -------------------------------------------------------------------------
return isinstance(value, int) and not isinstance(value, bool)
2017-03-09 01:10:28 +01:00
2019-07-31 20:08:05 +02:00
def _pylg_check_nonneg_int(value):
return _pylg_check_int(value) and value >= 0
2017-03-17 00:17:34 +01:00
2019-07-31 20:08:05 +02:00
def _pylg_check_pos_int(value):
return _pylg_check_int(value) and value > 0