Improve Config file validation and error messages
This commit is contained in:
parent
c31c452f7e
commit
42f8e5c2d7
3 changed files with 92 additions and 107 deletions
|
@ -52,7 +52,7 @@ pip install wallman
|
|||
#+END_SRC
|
||||
|
||||
** Installing manually
|
||||
+ Install libnotify and feh, (preferably, also install the python dependecies from there) from your package manager
|
||||
+ Install libnotify and feh, (preferably, also install the python dependencies from there) from your package manager
|
||||
#+BEGIN_SRC shell
|
||||
git clone https://git.entheuer.de/emma/Wallman.git
|
||||
cd Wallman/
|
||||
|
@ -65,6 +65,7 @@ mkdir -p ~/.config/wallman
|
|||
cp sample_config.toml ~/.config/wallman/wallman.toml
|
||||
sudo mkdir -p /etc/wallman/
|
||||
sudo cp -r icons /etc/wallman
|
||||
sudo cp -r DefaultFallbackWallpaper /etc/wallman/DefaultFallbackWallpaper.jpg
|
||||
python -m build
|
||||
sudo python -m installer --destdir=/ dist/*.whl
|
||||
#+END_SRC
|
||||
|
@ -85,8 +86,8 @@ In general, you need to always define 3 variables and you can optionally add thr
|
|||
The amount of wallpapers that you use in each set. It should be an integer.
|
||||
+ Optional: notify: bool
|
||||
This defaults to "false". Enable to set send a desktop notification when the wallpaper is changed. The program will still work correctly, even if this option is not defined at all.
|
||||
+ Optional: fallback_wallpaper: bool
|
||||
Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to None. If none is set and the config has been written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will exit with Code 1. If The config is written correctly but the wallpaper intended to be set can't be found, wallman will set the fallback wallpaper and continue to try setting future wallpapers.
|
||||
+ Optional: fallback_wallpaper: string
|
||||
Wallpaper to be set if an error is found in the config or the wallpaper intended to be set cannot be found. Defaults to "/etc/wallman/DefaultFallbackWallpaper.jpg". If none is set and the config has been written incorrectly, a ConfigError is raised and the program is exited. If an error in the config occurs but the fallback wallpaper has been defined, it will be set and wallman will raise a config error. If The config is written correctly but the wallpaper intended to be set can't be found, wallman will set the fallback wallpaper and continue to try setting future wallpapers. You can both change this location (recommended) or the wallpaper that the path points to.
|
||||
+ Optional: loglevel: string
|
||||
Loglevel to be used by wallman. Defaults to INFO. Choices MUST be DEBUG, INFO, WARNING, ERROR or CRITICAL. Using any capitalization is valid, all caps is reccomended. Wallman will crash if a value is specified that is not one of the specified ones.
|
||||
+ Optional: systray: bool
|
||||
|
@ -116,7 +117,6 @@ The keys in the dictionary once again do not matter, the names of the keys in ea
|
|||
|
||||
** Technical Details
|
||||
+ Improve Modularity (Partially done)
|
||||
+ Make the enabled flag in wallpaper_sets actually useful by making the used_sets field optional
|
||||
+ Drop the feh dependecy and set wallpapers using pywlroots or python-xlib
|
||||
|
||||
** Features
|
||||
|
|
|
@ -5,7 +5,7 @@ enable_wallpaper_sets = true
|
|||
used_sets = ["anime", "nature"]
|
||||
wallpapers_per_set = 5
|
||||
notify = false
|
||||
fallback_wallpaper = "/etc/wallman/DefaultFallbackWallpaper.jpg"
|
||||
fallback_wallpaper = "/etc/wallman/DefaultFallbackWallpaper.jpg" # Feel free to use a different filepath for this!
|
||||
loglevel = "INFO"
|
||||
systray = true
|
||||
behavior = "fill"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from sys import exit
|
||||
from os import chdir, getenv, system, path
|
||||
import logging
|
||||
import tomllib
|
||||
|
@ -14,36 +13,26 @@ global logger
|
|||
logger = logging.getLogger("wallman")
|
||||
|
||||
class _Config:
|
||||
# Initializes the most important config values. TODO: Add handling for the empty config edge case and the FileNotFound case
|
||||
# Initializes the most important config values.
|
||||
def __init__(self) -> None:
|
||||
# Config file
|
||||
self.config_file: ConfigFile = self._initialize_config() # Full config
|
||||
# Dictionaries
|
||||
self.config_general: ConfigGeneral = self.config_file["general"]
|
||||
self.config_changing_times: Dict[str, str] = self.config_file["changing_times"]
|
||||
# Values in Dicts
|
||||
self.config_wallpaper_sets_enabled: bool = self.config_general["enable_wallpaper_sets"]
|
||||
self.config_used_sets: List[str] = self.config_general["used_sets"]
|
||||
self.config_wallpapers_per_set: int = self.config_general["wallpapers_per_set"]
|
||||
# Config general
|
||||
valid_general: bool = self._initialize_general()
|
||||
if not valid_general:
|
||||
logger.critical("The general dictionary was not found or contains errors")
|
||||
print("CRITICAL: The general dictionary was not found or contains errors")
|
||||
raise ConfigError("The general dictionary was not found or contains errors")
|
||||
# Changing times
|
||||
valid_changing_times: bool = self._initialize_changing_times()
|
||||
if not valid_changing_times:
|
||||
logger.critical("The amount of provided changing times does not match the amount of wallpapers per set, or the dictionary has not been found in the config file.")
|
||||
print("CRITICAL: The amount of provided changing times does not match the amount of wallpapers per set, or the dictionary has not been found in the config file.")
|
||||
self.config_total_changing_times: int = len(self.config_changing_times)
|
||||
self.config_log_level: str = self.config_general.get("loglevel", "INFO").upper()
|
||||
self.config_behavior: str = self._set_behavior()
|
||||
# Setup logging
|
||||
self._set_log_level()
|
||||
# HACK: Add a function to handle these try/except blocks cleanlier.
|
||||
try:
|
||||
self.config_notify: bool = self.config_general["notify"]
|
||||
except KeyError:
|
||||
self.config_notify: bool = False
|
||||
logger.warning("'notify' is not set in dictionary general in the config file, defaulting to 'false'.")
|
||||
try:
|
||||
self.config_systray: bool = self.config_general["systray"]
|
||||
except KeyError:
|
||||
self.config_systray: bool = True
|
||||
logger.warning("'systray' is not set in the dictionary general in the config file, defaulting to 'true'.")
|
||||
|
||||
# Setup systray.
|
||||
if self.config_systray:
|
||||
self._verify_systray_deps()
|
||||
# Wallpaper sets
|
||||
valid_wallpaper_amount: bool = self._check_wallpaper_amount()
|
||||
if not valid_wallpaper_amount:
|
||||
raise ConfigError("The amount of wallpapers in a set does not match the amount of wallpapers_per_set provided in general.")
|
||||
|
||||
# Read config
|
||||
def _initialize_config(self) -> ConfigFile:
|
||||
|
@ -109,12 +98,13 @@ class _Config:
|
|||
return behavior
|
||||
|
||||
def _set_fallback_wallpaper(self) -> None:
|
||||
if self.config_general["fallback_wallpaper"]:
|
||||
system(f"feh {self.config_behavior} --no-fehbg {self.config_general['fallback_wallpaper']}")
|
||||
logger.info("The fallback Wallpaper has been set.")
|
||||
else:
|
||||
logger.critical("An Error occured and no fallback wallpaper was provided, exiting...")
|
||||
raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...")
|
||||
if self.config_fallback_wallpaper:
|
||||
successfully_set: int = system(f"feh {self.config_behavior} --no-fehbg {self.config_fallback_wallpaper}")
|
||||
if successfully_set == 0:
|
||||
logger.info("The fallback Wallpaper has been set.")
|
||||
else:
|
||||
logger.critical("An Error occured and no fallback wallpaper was provided, exiting...")
|
||||
raise ConfigError("An error occured and no fallback wallpaper has been set, exiting...")
|
||||
|
||||
def _initialize_general(self) -> bool:
|
||||
# Create Config General Dict
|
||||
|
@ -122,32 +112,75 @@ class _Config:
|
|||
self.config_general: ConfigGeneral = self.config_file["general"]
|
||||
except KeyError:
|
||||
print("CRITICAL: No general dictionary found in Config file.")
|
||||
return False
|
||||
raise ConfigError("The general dictionary could not be found in the config, exiting!")
|
||||
# Set up logger.
|
||||
self.config_log_level = self.config_general.get("log_level", "INFO").upper()
|
||||
self._set_log_level()
|
||||
logger.debug(f"Log level has been set to {self.config_log_level}")
|
||||
logger.debug("Logger initialized successfully")
|
||||
# Set up fallback wallpaper
|
||||
self.config_fallback_wallpaper: str = self.config_general.get("fallback_wallpaper", "/etc/wallman/DefaultFallbackWallpaper.jpg")
|
||||
logger.debug(f"Set fallback wallpaper: {self.config_fallback_wallpaper}")
|
||||
# Wallpapers per set
|
||||
try:
|
||||
self.config_wallpapers_per_set: int = self.config_general["wallpapers_per_set"]
|
||||
logger.debug(f"Set config_wallpapers_per_set to {self.config_wallpapers_per_set}")
|
||||
except KeyError:
|
||||
print("CRITICAL: No option wallpapers_per_set provided in the general dictionary. Attempting to set the fallback wallpaper")
|
||||
logger.critical("No option wallpapers_per_set provided in the general dictionary. Attempting to set the fallback wallpaper")
|
||||
self._set_fallback_wallpaper()
|
||||
return False
|
||||
# Are wallpaper sets enabled to begin with?
|
||||
try:
|
||||
self.config_wallpaper_sets_enabled: bool = self.config_general["enable_wallpaper_sets"]
|
||||
logger.debug(f"Set config_wallpaper_sets_enabled to {self.config_wallpaper_sets_enabled}")
|
||||
except KeyError:
|
||||
logger.critical("No option enable_wallpaper_sets provided in the general dictionary. Attempting to set the fallback wallpaper")
|
||||
print("CRITICAL: No option enable_wallpaper_sets provided in the general dictionary. Attempting to set the fallback wallpaper")
|
||||
self._set_fallback_wallpaper()
|
||||
return False
|
||||
# Configure used sets
|
||||
if self.config_wallpaper_sets_enabled:
|
||||
try:
|
||||
self.config_used_sets: List[str] = self.config_general["used_sets"]
|
||||
logger.debug(f"These wallpaper sets are in use: {self.config_used_sets}")
|
||||
except KeyError:
|
||||
print("CRITICAL: No array used_sets provided in the general dictionary. Attempting to set the fallback wallpaper.")
|
||||
logger.critical("No array used_sets provided in the general dictionary. Attempting to set the fallback wallpaper.")
|
||||
self._set_fallback_wallpaper()
|
||||
return False
|
||||
# Systray
|
||||
try:
|
||||
self.config_systray: bool = self.config_general["systray"]
|
||||
logger.debug(f"config_systray has been set to: {self.config_systray}")
|
||||
except KeyError:
|
||||
self.config_systray: bool = True
|
||||
logger.warning("No option systray found in general. Defaulting to true...")
|
||||
if self.config_systray:
|
||||
self._verify_systray_deps()
|
||||
# Wallpaper behavior
|
||||
self.config_behavior = self._set_behavior()
|
||||
# Notifications
|
||||
try:
|
||||
self.config_notify: bool = self.config_general["notify"]
|
||||
logger.debug(f"Set config_notify to {self.config_notify}.")
|
||||
except KeyError:
|
||||
self.config_notify: bool = False
|
||||
logger.warning("notify is not set in dictionary general in the config file, defaulting to 'false'.")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ConfigValidity(_ConfigLib):
|
||||
# TODO: Add handling for the empty config case.
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def _check_fallback_wallpaper(self) -> bool:
|
||||
# TODO: Make self.config_general["fallback_wallpaper"] a class-wide variable in ConfigLib
|
||||
if self.config_general["fallback_wallpaper"]:
|
||||
logger.debug("A fallback wallpaper has been defined.")
|
||||
return True
|
||||
else:
|
||||
logger.warning("No fallback wallpaper has been provided. If the config is written incorrectly, the program will not be able to be executed.")
|
||||
def _initialize_changing_times(self) -> bool:
|
||||
try:
|
||||
self.config_changing_times: Dict[str, str] = self.config_file["changing_times"]
|
||||
logger.debug(f"Changing times are {self.config_changing_times}")
|
||||
except KeyError:
|
||||
logger.critical("No dictionary called changing_times has been found in the config file.")
|
||||
print("CRITICAL: No dictionary called changing_times has been found in the config file.")
|
||||
return False
|
||||
return self._wallpapers_per_set_and_changing_times_match()
|
||||
|
||||
def _check_wallpapers_per_set_and_changing_times(self) -> bool:
|
||||
def _wallpapers_per_set_and_changing_times_match(self) -> bool:
|
||||
# Check if the amount of wallpapers_per_set and given changing times match
|
||||
if self.config_total_changing_times == self.config_wallpapers_per_set:
|
||||
logger.debug("The amount of changing times and wallpapers per set is set correctly")
|
||||
|
@ -155,47 +188,13 @@ class ConfigValidity(_ConfigLib):
|
|||
else:
|
||||
try:
|
||||
self._set_fallback_wallpaper()
|
||||
logger.error("The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set.")
|
||||
print("ERROR: The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set.")
|
||||
logger.critical("The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set.")
|
||||
print("CRITICAL: The amount of changing_times and the amount of wallpapers_per_set does not match, the fallback wallpaper has been set.")
|
||||
return False
|
||||
except ConfigError:
|
||||
logger.critical("The amount of changing times and the amount of wallpapers per set does not match, exiting...")
|
||||
raise ConfigError("Please provide an amount of changing_times equal to wallpapers_per_set, exiting...")
|
||||
|
||||
def _check_general_validity(self) -> bool:
|
||||
# FIXME!
|
||||
# TODO: Adjust it to check for the actually required variables existing rather than check if a number of options is set, which is highly error prone.
|
||||
if len(self.config_general) < 3:
|
||||
try:
|
||||
self._set_fallback_wallpaper()
|
||||
logger.error("An insufficient amount of elements has been provided for general, the fallback wallpaper has been set.")
|
||||
print("ERROR: An insufficient amount of wallpapers has been provided for general, the fallback wallpaper has been set.")
|
||||
return False
|
||||
except ConfigError:
|
||||
logger.critical("An insufficient amount of elements for general has been provided, exiting...")
|
||||
raise ConfigError("general should have at least 3 elements, exiting...")
|
||||
|
||||
else:
|
||||
logger.debug("A valid amount of options has been provided in general")
|
||||
return True
|
||||
|
||||
def _check_wallpaper_dicts(self) -> bool:
|
||||
# This block checks if a dictionary for each wallpaper set exists
|
||||
for wallpaper_set in self.config_used_sets:
|
||||
if wallpaper_set in self.config_file:
|
||||
logger.debug(f"The dictionary {wallpaper_set} has been found in config.")
|
||||
return True
|
||||
# TODO split this into smaller pieces. This goes too deep.
|
||||
else:
|
||||
try:
|
||||
self._set_fallback_wallpaper()
|
||||
logger.error(f"The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
|
||||
print(f"ERROR: The dictionary {wallpaper_set} has not been found in the config, the fallback wallpaper has been set.")
|
||||
return False
|
||||
except ConfigError:
|
||||
logger.critical(f"No dictionary {wallpaper_set} has been found in the config exiting...")
|
||||
raise ConfigError(f"The dictionary {wallpaper_set} has not been found in the config, exiting...")
|
||||
return False
|
||||
print("CRITICAL: The amount of changing times and the amount of wallpapers per set does not match, exiting...")
|
||||
raise ConfigError("The amount of changing times and the amount of wallpapers per set does not match.")
|
||||
|
||||
def _check_wallpaper_amount(self) -> bool:
|
||||
# This block checks if if each wallpaper set dictionary provides enough wallpapers to satisfy wallpapers_per_set
|
||||
|
@ -211,23 +210,9 @@ class ConfigValidity(_ConfigLib):
|
|||
return False
|
||||
except ConfigError:
|
||||
logger.critical(f"Dictionary {wallpaper_set} does not have sufficient entries, exciting...")
|
||||
raise ConfigError(f"Dictionary {wallpaper_set} does not have the correct amount of entries, exciting...")
|
||||
print(f"Dictionary {wallpaper_set} does not have sufficient entries, exciting...")
|
||||
return False
|
||||
|
||||
def validate_config(self) -> bool:
|
||||
# HACK: Consider using different exit codes for different errors to help users debug.
|
||||
if not self._check_fallback_wallpaper():
|
||||
pass
|
||||
if not self._check_wallpapers_per_set_and_changing_times():
|
||||
exit(1)
|
||||
if not self._check_general_validity():
|
||||
exit(1)
|
||||
if not self._check_wallpaper_dicts():
|
||||
exit(1)
|
||||
if not self._check_wallpaper_amount():
|
||||
exit(1)
|
||||
logger.debug("The config file has been validated successfully (No Errors)")
|
||||
return True
|
||||
|
||||
# TODO: Improve modularity. See notes inside the class for more details.
|
||||
# TODO: Ensure functionality and if needed add handling for the 1 wallpaper per set case.
|
||||
|
|
Loading…
Reference in a new issue