feat: create config class to replace use of config file in application

This commit is contained in:
WorldTeacher
2024-10-29 16:07:30 +01:00
parent 2137799f9b
commit f3eed7486d
13 changed files with 224 additions and 111 deletions

View File

@@ -1,62 +0,0 @@
default_apps: true
save_path: ~/Desktop/semap/db/temp/
icon_path: icons/
zotero:
api_key:
library_id: ""
library_type: user
custom_applications:
- name: Text files
extensions:
- txt
- md
- rst
application: Notepad
- name: CSV files
extensions:
- csv
application: Excel
- name: pdf files
extensions:
- pdf
application: Firefox
- name: Word files
extensions:
- docx
- doc
application: Word
- name: Excel files
extensions:
- xlsx
- xls
application: Excel
database:
name: test.sam
path: ~\Desktop\semap\db\
tempdir: ~\Desktop\semap\db\temp\
mail:
smtp_server: ''
port: 0
sender: ''
user_name: ''
use_user_name: false
password: ''
signature: '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style
type="text/css">
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: "\2610"; }
li.checked::marker { content: "\2612"; }
</style></head><body style=" font-family:''Segoe UI''; font-size:9pt; font-weight:400;
font-style:normal;">
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>'

1
config/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .config import Config

167
config/config.py Normal file
View File

@@ -0,0 +1,167 @@
from typing import Optional
from dataclasses import dataclass
from omegaconf import OmegaConf, DictConfig
import os
@dataclass
class Zotero:
api_key: str
library_id: str
library_type: str
def getattr(self, name):
return getattr(self, name)
def _setattr(self, name, value):
setattr(self, name, value)
@dataclass
class Database:
name: str
path: str
tempdir: str
def getattr(self, name):
return getattr(self, name)
def _setattr(self, name, value):
setattr(self, name, value)
@dataclass
class Mail:
smtp_server: str
port: int
sender: str
password: str
use_user_name: bool
user_name: str
signature: str
empty_signature = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style
type="text/css">
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: "\2610"; }
li.checked::marker { content: "\2612"; }
</style></head><body style=" font-family:''Segoe UI''; font-size:9pt; font-weight:400;
font-style:normal;">
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""
def getattr(self, name):
return getattr(self, name)
def _setattr(self, name, value):
setattr(self, name, value)
class Config:
'''A class to handle the configuration of the application. After initializing, it will try to load the config file and store it for future access. Any changes made can be saved to the file using the .save() method. Changes are used in real time in the app, if a restart is required, the Application will show a window.
Raises:
RuntimeError: Configuration not loaded
KeyError: Invalid option
'''
_config: Optional[DictConfig] = None
def __init__(self, config_path: str):
"""
Loads the configuration file and stores it for future access.
Args:
config_path (str): Path to the YAML configuration file.
Raises:
FileNotFoundError: Configuration file not found
"""
if not os.path.exists(config_path):
raise FileNotFoundError(f"Configuration file not found: {config_path}")
self._config = OmegaConf.load(config_path)
self.config_path = config_path
def save(self):
"""
Saves the current configuration to the file.
Args:
config_path (str): Path to the YAML configuration file.
"""
OmegaConf.save(self._config, self.config_path)
@property
def zotero(self):
return Zotero(**self._config.zotero)
@property
def zotero_attr(self, name):
return getattr(self.zotero, name)
@zotero_attr.setter
def zotero_attr(self, name, value):
self.zotero._setattr(name, value)
@property
def database(self):
return Database(**self._config.database)
@property
def database_attr(self, name):
return getattr(self.database, name)
@database_attr.setter
def database_attr(self, name, value):
self.database._setattr(name, value)
@property
def mail(self):
return Mail(**self._config.mail)
def mail_attr(self, name):
return getattr(self.mail, name)
def set_mail_attr(self, name, value):
OmegaConf.update(self._config, f"mail.{name}", value)
def set_database_attr(self, name, value):
OmegaConf.update(self._config, f"database.{name}", value)
def set_zotero_attr(self, name, value):
OmegaConf.update(self._config, f"zotero.{name}", value)
@property
def default_apps(self):
return self._config.default_apps
@default_apps.setter
def default_apps(self, value: bool):
self._config.default_apps = value
@property
def save_path(self):
return self._config.save_path
@save_path.setter
def save_path(self, value: str):
self._config.save_path = value
@property
def icon_path(self):
"""Path to Icon folder
Returns:
str: Folder path as string
"""
return self._config.icon_path

View File

@@ -1,7 +1,11 @@
__version__ = "1.0.0" __version__ = "1.0.0"
__author__ = "Alexander Kirchner" __author__ = "Alexander Kirchner"
from config import Config
settings = Config("config/config.yaml")
from .utils.icon import Icon
from .logic.log import MyLogger from .logic.log import MyLogger
from .utils.icon import Icon
from .ui.userInterface import launch_gui as UI from .ui.userInterface import launch_gui as UI

View File

@@ -2,12 +2,10 @@ import os
from pathlib import Path from pathlib import Path
from icecream import ic from icecream import ic
from omegaconf import OmegaConf
from src.backend.database import Database from src.backend.database import Database
db = Database() db = Database()
config = OmegaConf.load("config.yaml")
def recreateFile(name, app_id, filetype, open=True) -> Path: def recreateFile(name, app_id, filetype, open=True) -> Path:

View File

@@ -3,6 +3,7 @@ import inspect
import sqlite3 as sql import sqlite3 as sql
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from src import database
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict, List, Optional, Tuple, Union
# from icecream import ic # from icecream import ic
from omegaconf import OmegaConf from omegaconf import OmegaConf
@@ -28,7 +29,7 @@ from src.utils import create_blob, dump_pickle, load_pickle
from .semester import generateSemesterByDate from .semester import generateSemesterByDate
from icecream import ic from icecream import ic
config = OmegaConf.load("config.yaml")
ascii_lowercase = "abcdefghijklmnopqrstuvwxyz0123456789)" ascii_lowercase = "abcdefghijklmnopqrstuvwxyz0123456789)"
caller_frame = inspect.stack()[1] caller_frame = inspect.stack()[1]
# get the line that called the function # get the line that called the function
@@ -54,14 +55,14 @@ class Database:
self.name = script_name self.name = script_name
self.logger = MyLogger(name) self.logger = MyLogger(name)
if db_path is None: if db_path is None:
self.db_path = config.database.path + config.database.name self.db_path = database.path + database.name
self.db_path = self.db_path.replace("~", str(Path.home())) self.db_path = self.db_path.replace("~", str(Path.home()))
else: else:
self.db_path = db_path self.db_path = db_path
self.checkDatabaseStatus() self.checkDatabaseStatus()
def checkDatabaseStatus(self): def checkDatabaseStatus(self):
path = config.database.path path = database.path
path = path.replace("~", str(Path.home())) path = path.replace("~", str(Path.home()))
# print(path) # print(path)
path = os.path.abspath(path) path = os.path.abspath(path)
@@ -507,7 +508,7 @@ class Database:
str: The filename of the recreated file str: The filename of the recreated file
""" """
blob = self.getBlob(filename, app_id) blob = self.getBlob(filename, app_id)
tempdir = config.database.tempdir tempdir = database.tempdir
tempdir = tempdir.replace("~", str(Path.home())) tempdir = tempdir.replace("~", str(Path.home()))
tempdir_path = Path(tempdir) tempdir_path = Path(tempdir)
if not os.path.exists(tempdir_path): if not os.path.exists(tempdir_path):
@@ -1414,7 +1415,7 @@ class Database:
"SELECT fileblob FROM elsa_files WHERE filename=?", (filename,), one=True "SELECT fileblob FROM elsa_files WHERE filename=?", (filename,), one=True
)[0] )[0]
# print(blob) # print(blob)
tempdir = config.database.tempdir tempdir = database.tempdir
tempdir = tempdir.replace("~", str(Path.home())) tempdir = tempdir.replace("~", str(Path.home()))
tempdir_path = Path(tempdir) tempdir_path = Path(tempdir)
if not os.path.exists(tempdir_path): if not os.path.exists(tempdir_path):

View File

@@ -1,16 +1,14 @@
import os import os
from pathlib import Path from pathlib import Path
from src import database
from omegaconf import OmegaConf
config = OmegaConf.load("config.yaml")
def delete_temp_contents(): def delete_temp_contents():
""" """
delete_temp_contents deletes the contents of the temp directory. delete_temp_contents deletes the contents of the temp directory.
""" """
path = config.database.tempdir path = database.tempdir
path = path.replace("~", str(Path.home())) path = path.replace("~", str(Path.home()))
path = Path(path) path = Path(path)
path = path.resolve() path = path.resolve()

View File

@@ -2,12 +2,11 @@ import sqlite3
from PyQt6.QtCore import QThread from PyQt6.QtCore import QThread
from PyQt6.QtCore import pyqtSignal as Signal from PyQt6.QtCore import pyqtSignal as Signal
from omegaconf import OmegaConf
from src.backend.database import Database from src.backend.database import Database
from src.logic.log import MyLogger from src.logic.log import MyLogger
from src.logic.webrequest import BibTextTransformer, WebRequest from src.logic.webrequest import BibTextTransformer, WebRequest
config = OmegaConf.load("config.yaml")
class BookGrabber(QThread): class BookGrabber(QThread):

View File

@@ -1,6 +1,5 @@
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from omegaconf import OmegaConf
# import sleep_and_retry decorator to retry requests # import sleep_and_retry decorator to retry requests
from ratelimit import limits, sleep_and_retry from ratelimit import limits, sleep_and_retry
@@ -10,7 +9,6 @@ from src.logic.log import MyLogger
from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData
logger = MyLogger(__name__) logger = MyLogger(__name__)
config = OmegaConf.load("config.yaml")
API_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndexrecord/{}/" API_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndexrecord/{}/"
PPN_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndex/Search?type0%5B%5D=allfields&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=au&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ti&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ct&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=isn&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ta&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=co&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=py&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pp&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pu&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=si&lookfor0%5B%5D={}&join=AND&bool0%5B%5D=AND&type0%5B%5D=zr&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=cc&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND" PPN_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndex/Search?type0%5B%5D=allfields&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=au&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ti&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ct&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=isn&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ta&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=co&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=py&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pp&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pu&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=si&lookfor0%5B%5D={}&join=AND&bool0%5B%5D=AND&type0%5B%5D=zr&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=cc&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND"

View File

@@ -1,10 +1,8 @@
from pyzotero import zotero from pyzotero import zotero
from dataclasses import dataclass from dataclasses import dataclass
from src.logic.webrequest import WebRequest, BibTextTransformer from src.logic.webrequest import WebRequest, BibTextTransformer
from omegaconf import OmegaConf from src import settings
config = OmegaConf.load("config.yaml")
config = config["zotero"]
@dataclass @dataclass
@@ -160,9 +158,12 @@ class JournalArticle:
class ZoteroController: class ZoteroController:
zoterocfg = settings.zotero
def __init__(self): def __init__(self):
self.zot = zotero.Zotero( self.zot = zotero.Zotero(
config["library_id"], config["library_type"], config["api_key"] self.zoterocfg.library_id,
self.zoterocfg.library_type,
self.zoterocfg.api_key,
) )
def get_books(self): def get_books(self):

View File

@@ -1,11 +1,9 @@
from omegaconf import OmegaConf
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6 import QtCore, QtGui, QtWidgets
from src import Icon from src import Icon, settings
from .dialog_sources.Ui_settings import Ui_Dialog as _settings from .dialog_sources.Ui_settings import Ui_Dialog as _settings
config = OmegaConf.load("config.yaml")
base = """'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> base = """'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style <html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style
@@ -61,18 +59,18 @@ class Settings(QtWidgets.QDialog, _settings):
self.buttonBox.accepted.connect(self.save) self.buttonBox.accepted.connect(self.save)
def load_config(self): def load_config(self):
self.db_name.setText(config.database.name) self.db_name.setText(settings.database.name)
self.db_path.setText(config.database.path) self.db_path.setText(settings.database.path)
self.save_path.setText(config.save_path) self.save_path.setText(settings.save_path)
self.smtp_address.setText(config.mail.smtp_server) self.smtp_address.setText(settings.mail.smtp_server)
self.smtp_port.setText(str(config.mail.port)) self.smtp_port.setText(str(settings.mail.port))
self.sender_email.setText(config.mail.sender) self.sender_email.setText(settings.mail.sender)
self.mail_username.setText(config.mail.user_name) self.mail_username.setText(settings.mail.user_name)
self.password.setText(config.mail.password) self.password.setText(settings.mail.password)
self.use_username_smtp_login.setChecked( self.use_username_smtp_login.setChecked(
config.mail.use_user_name if config.mail.use_user_name else False settings.mail.use_user_name if settings.mail.use_user_name else False
) )
self.editSignature.setHtml(config.mail.signature) self.editSignature.setHtml(settings.mail.signature)
def setCurrentFont(self): def setCurrentFont(self):
font = self.fontComboBox.currentFont() font = self.fontComboBox.currentFont()
@@ -148,22 +146,28 @@ class Settings(QtWidgets.QDialog, _settings):
signature = signature signature = signature
else: else:
signature = "" signature = ""
config.database.name = self.db_name.text() settings.set_database_attr("name", self.db_name.text())
config.database.path = self.db_path.text() settings.set_database_attr("path", self.db_path.text())
config.save_path = self.save_path.text() settings.save_path = self.save_path.text()
config.mail.smtp_server = self.smtp_address.text() settings.set_mail_attr("smtp_server", self.smtp_address.text())
config.mail.port = port settings.set_mail_attr("port", port)
config.mail.sender = self.sender_email.text() settings.set_mail_attr("sender", self.sender_email.text())
config.mail.user_name = self.mail_username.text() settings.set_mail_attr("user_name", self.mail_username.text())
config.mail.password = self.password.text() settings.set_mail_attr("password", self.password.text())
config.mail.use_user_name = self.use_username_smtp_login.isChecked() settings.set_mail_attr(
config.mail.signature = signature "use_user_name", self.use_username_smtp_login.isChecked()
)
return config settings.set_mail_attr("signature", signature)
print("Settings:")
print(settings)
return settings
def save(self): def save(self):
config = self.return_data() config = self.return_data()
OmegaConf.save(config, "config.yaml") print(config.mail)
print("Saving config")
print(config)
config.save()
self.accept() self.accept()

View File

@@ -1,7 +1,7 @@
from PyQt6 import QtWidgets, QtCore from PyQt6 import QtWidgets, QtCore
from src.backend.database import Database
from PyQt6.QtCore import QDate from PyQt6.QtCore import QDate
from PyQt6.QtGui import QColor, QPen from PyQt6.QtGui import QColor, QPen
from src.backend import Database
import darkdetect import darkdetect
from icecream import ic from icecream import ic

View File

@@ -2,8 +2,12 @@ import darkdetect
from omegaconf import OmegaConf from omegaconf import OmegaConf
from PyQt6 import QtGui from PyQt6 import QtGui
import re import re
config = OmegaConf.load("config.yaml")
config = OmegaConf.load(f"{config.icon_path}/icons.yaml") from config import Config
settings = Config("config/config.yaml")
config = OmegaConf.load(f"{settings.icon_path}/icons.yaml")
path = config.icon_path path = config.icon_path