From 31a7740760ca741310bf32e54310d8c00784ae1d Mon Sep 17 00:00:00 2001 From: Hellow <74311245+HeIIow2@users.noreply.github.com> Date: Mon, 14 Aug 2023 23:30:39 +0200 Subject: [PATCH] implemented basis for config --- documentation/config.md | 53 +++++++++ src/music_kraken/_settings/__init__.py | 0 src/music_kraken/_settings/base_models.py | 127 ++++++++++++++++++++++ src/music_kraken/utils/config.py | 29 ++++- 4 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 documentation/config.md create mode 100644 src/music_kraken/_settings/__init__.py create mode 100644 src/music_kraken/_settings/base_models.py diff --git a/documentation/config.md b/documentation/config.md new file mode 100644 index 0000000..b1313dc --- /dev/null +++ b/documentation/config.md @@ -0,0 +1,53 @@ +> This is bs, ima use dynaconf + +# Concept + +The core concept is, to have instances of dataclasses that hold all values. On programm start the values are just overridden by those in the file. + +## Dataclass Structure + +You have one [File](#file) class, that contains a list of [Section](#section) classes. +Every [Section](#section) class contains a list of [SectionElement](#section-elements) classes. + +# Classes + +## File + +`File` classes have one name, with whom the path will be generated: + +``` +{CONFIG_DIR}/{file_name}.conf +``` + +I also pass in the config direcory in the constructor, such that the module can be pretty independently used. Though it's default value is the default config director from `utils.path_manager`. + + +They contain a list of [ConfigElement](#config-elements)s, arguably the most important ones. + +## Config Elements + +# Config Syntax + +- every line is stripped from all whitespaces at the beginning and end + +``` +# a comment + +config_name=some_value + +# list +[config_name.list.start] +config_name=one list item +config_name=another list item +[config_name.list.end] + +# dict +[config_name.dict.start] +one_key=one value item +another_key=another value item +[config_name.dict.end] +``` + +- empty lines will be ignored +- If `#` is at the beginning of the line, it will be ignored +- if there is neither a `\[.*\]` or a `=` in a line, it will raise a warning, but will be ignored diff --git a/src/music_kraken/_settings/__init__.py b/src/music_kraken/_settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/music_kraken/_settings/base_models.py b/src/music_kraken/_settings/base_models.py new file mode 100644 index 0000000..59b36c2 --- /dev/null +++ b/src/music_kraken/_settings/base_models.py @@ -0,0 +1,127 @@ +from typing import Optional, List, Union, Dict +from collections.abc import Iterable +from pathlib import Path + +import toml + + +def comment_string(uncommented_string: str) -> str: + _fragments = uncommented_string.split("\n") + _fragments = ["# " + frag for frag in _fragments] + return "\n".join(_fragments) + + +class Comment: + def __init__(self, value: str) -> None: + self.value: str = value + + @property + def uncommented(self) -> str: + return self.value + + @property + def commented(self) -> str: + return comment_string(self.value) + + def __str__(self) -> str: + return self.commented + + +class Attribute: + def __init__(self, data: dict, comment: Optional[str] = None) -> None: + self.data: dict = data + self.comment: Optional[Comment] = None if comment is None else Comment( + comment) + + @property + def toml_string(self) -> str: + _data_string = toml.dumps(self.data) + components: List[str] = [_data_string] + + if self.comment is not None: + components.append(self.comment.commented) + + return "\n".join(components) + + def __setitem__(self, key: str, value): + if key not in self.data: + self.data[key] = value + + if isinstance(self.data[key], dict) and isinstance(value, dict): + self.data[key].update(value) + + self.data[key] = value + + +class ConfigFile: + def __init__(self, config_file: Path, data: List[Union[Attribute, Comment]]) -> None: + self.config_file: Path = config_file + + self.unknown_attribute: Attribute = Attribute( + {}, "This is the attribute is for all unknown attributes.") + + self._data: List[Union[Attribute, Comment]] = data + self._key_attribute_map: Dict[str, Attribute] = {} + for attribute in self._data: + if isinstance(attribute, Comment): + continue + + for key in attribute.data: + self._key_attribute_map[key] = attribute + + def load(self): + self.update(toml.load(self.config_file.open("r"), encoding="utf-8")) + + def dump(self): + with self.config_file.open("w", encoding="utf-8") as config_file: + config_file.write(self.toml_string) + + def update(self, data: dict): + for key, value in data.items(): + if key not in self._key_attribute_map: + self._key_attribute_map[key] = self.unknown_attribute + self.unknown_attribute[key] = value + continue + + self._key_attribute_map[key][key] = value + + @property + def toml_string(self) -> str: + components: List[str] = [] + for attribute in self._data: + if isinstance(attribute, Attribute): + components.append(attribute.toml_string) + + components.append(self.unknown_attribute.toml_string) + + return "\n\n".join(components) + + def __str__(self) -> str: + return self.toml_string + + +if __name__ == "__main__": + settings = ConfigFile(Path("/home/lars/.config/music-kraken/music-kraken.toml"), [ + Attribute({ + "happy_message": [ + "Support the artist.", + "Star Me: https://github.com/HeIIow2/music-downloader", + "🏳️‍⚧️🏳️‍⚧️ Trans rights are human rights. 🏳️‍⚧️🏳️‍⚧️", + "🏳️‍⚧️🏳️‍⚧️ Trans women are women, trans men are men, and enbies are enbies. 🏳️‍⚧️🏳️‍⚧️", + "🏴‍☠️🏴‍☠️ Unite under one flag, fck borders. 🏴‍☠️🏴‍☠️", + "Join my Matrix Space: https://matrix.to/#/#music-kraken:matrix.org", + "Gotta love the BPJM ;-;", + "🏳️‍⚧️🏳️‍⚧️ Protect trans youth. 🏳️‍⚧️🏳️‍⚧️", + "Nonstop Progressive Marxism.", + ], + "bitrate": 66.6 + }, + comment="this is a test section" + ), + Attribute({ + "# hihi": "byebey" + }) + ]) + + print(settings) + settings.dump() diff --git a/src/music_kraken/utils/config.py b/src/music_kraken/utils/config.py index 026d43b..b0dd4a0 100644 --- a/src/music_kraken/utils/config.py +++ b/src/music_kraken/utils/config.py @@ -1,6 +1,8 @@ from dynaconf import Dynaconf +from dynaconf import settings +from dynaconf.utils import object_merge -from .path_manager import LOCATIONS +# from .path_manager import LOCATIONS """ https://www.dynaconf.com/settings_files/ @@ -12,6 +14,27 @@ The concept is that I package a config file, with this programm, and then load i Then I check if there is a config file at the LOCATIONS.CONFIG_FILE, and if yes they get merged """ -settings = Dynaconf( - settings_files=[str(LOCATIONS.CONFIG_FILE)], +settings.happy_message = [ + "Support the artist.", + "Star Me: https://github.com/HeIIow2/music-downloader", + "🏳️‍⚧️🏳️‍⚧️ Trans rights are human rights. 🏳️‍⚧️🏳️‍⚧️", + "🏳️‍⚧️🏳️‍⚧️ Trans women are women, trans men are men, and enbies are enbies. 🏳️‍⚧️🏳️‍⚧️", + "🏴‍☠️🏴‍☠️ Unite under one flag, fck borders. 🏴‍☠️🏴‍☠️", + "Join my Matrix Space: https://matrix.to/#/#music-kraken:matrix.org", + "Gotta love the BPJM ;-;", + "🏳️‍⚧️🏳️‍⚧️ Protect trans youth. 🏳️‍⚧️🏳️‍⚧️", + "Nonstop Progressive Marxism.", + ] + + +dynacont_object = Dynaconf( + settings_files=[str(LOCATIONS.CONFIG_FILE)] ) + + + +class Settings: + def __init__(self) -> None: + + +