I have a settings file, which is loaded in once and takes the values from the settings json file and uses them as the attribute values. I was thinking of using the @property
instead of overriding __getattribute__
but I feel as if there is a better, more elegant solution. Note that the application it is used in is multi-threaded.
settings.py
class SettingsMeta(type, JsonFileWrapperBase):
_file_path = os.path.join(os.getcwd(), "..", "data", "settings.json")
# Declarations to avoid PyCharm highlighting
manga_save_dir, database_path, total_scrapper_threads, log_file = None, None, None, None
_default_data = {
"manga_save_dir": r"D:\dir",
"database_path": r"D:\db.sqlite3",
"log_file": os.path.join(os.getcwd(), "..", "data", "log.log"),
"total_scrapper_threads": 1
}
@classmethod
def __getattribute__(mcs, item):
data = mcs._get_data()
if item in data:
return data[item]
elif hasattr(mcs, item):
return getattr(mcs, item)
raise AttributeError(f"Settings has no attribute {item}")
class Settings(metaclass=SettingsMeta):
pass
json_file_wrapper_base.py
class JsonFileWrapperBase:
_loaded_data = None
_file_path = ""
_default_data = ""
@classmethod
def _write_default(cls):
cls._write_data(cls._default_data)
@classmethod
def _write_data(cls, d):
os.makedirs(os.path.dirname(os.path.abspath(cls._file_path)), exist_ok=True)
try:
with open(cls._file_path, "w") as f:
json.dump(d, f)
except FileNotFoundError as e:
print(e)
@classmethod
def _get_data(cls):
"""
Reads and caches the JSON file, if the file has already been cached then return the cached file, I cache
the file to avoid users editing the file during execution and causing errors
"""
# File has not been cached yet
if cls._loaded_data is None:
cls._read_file()
return cls._loaded_data
@classmethod
def _read_file(cls) -> bool:
assert cls._loaded_data is None, "_read_file should only be called once per object"
# File doesn't exist or is not valid
if not os.path.isfile(cls._file_path):
cls._write_default()
try:
with open(cls._file_path, "r") as f:
data = json.load(f)
print(f"Log: Loaded {cls._file_path}")
cls._loaded_data = data
except FileNotFoundError as e:
print(e)
return False
return True
JsonFileWrapperBase._get_data
. \$\endgroup\$