Код: Выделить всё
from typing import Any
import os
import json
import logging
logger = logging.getLogger("config_manager")
class Descriptor:
def __init__(self, name, config_file):
self.name = name
self.config_file = config_file
def _read_config(self):
if os.path.exists(self.config_file):
with open(self.config_file, "r") as file:
return json.load(file)
return {}
def _write_config(self, config):
with open(self.config_file, "w") as file:
json.dump(config, file, indent=4)
def __get__(self, instance, owner):
config = self._read_config()
keys = self.name.split(".")
value = config
for key in keys:
value = value.get(key, {})
print(f"Accessing {self.name} from {owner}: {value}")
return value
def __set__(self, instance, value):
config = self._read_config()
keys = self.name.split(".")
d = config
for key in keys[:-1]:
if key not in d:
d[key] = {}
d = d[key]
d[keys[-1]] = value
self._write_config(config)
print(f"Setting {self.name} to {value}")
class DescriptorMeta(type):
def __new__(cls, name: str, bases: tuple[type, ...], dct: dict[str, Any]):
config_file = dct.get("config_file", "config.json")
for attr_name, attr_value in dct.items():
if isinstance(attr_value, type):
cls._process_group(attr_name, attr_value, config_file)
elif not attr_name.startswith("__") and not callable(attr_value):
dct[attr_name] = Descriptor(attr_name, config_file)
return super().__new__(cls, name, bases, dct)
@staticmethod
def _process_group(base_name: str, group_class: type, config_file: str):
for attr_name, attr_value in group_class.__dict__.items():
if not attr_name.startswith("__") and not callable(attr_value):
if isinstance(attr_value, type):
DescriptorMeta._process_group(attr_name, attr_value, config_file)
else:
setattr(group_class, attr_name, Descriptor(f"{base_name}.{attr_name}", config_file))
class Config(metaclass=DescriptorMeta):
config_file = "config.json"
theme_path = "default_theme"
class Colors:
base_color = "white"
class Geometry:
class Size:
height = 200
width = 800
# Accessing and setting top-level attributes
print(Config.theme_path) # Accessing theme_path from
config = Config()
print(config.theme_path) # Accessing theme_path from
Config.theme_path = "new_theme" # Setting theme_path to new_theme
print(Config.theme_path) # Accessing theme_path from
# Accessing and setting nested attributes
print(Config.Colors.base_color) # Accessing Colors.base_color from
config.Colors.base_color = "blue" # Setting Colors.base_color to blue
print(config.Colors.base_color) # Accessing Colors.base_color from
print(Config.Geometry.Size.height) # Accessing Geometry.Size.height from
config.Geometry.Size.height = 1024 # Setting Geometry.Size.height to 1024
print(config.Geometry.Size.height) # Accessing Geometry.Size.height from
Код: Выделить всё
Config.theme_path = "new_theme"). Похоже, что значение присваивается атрибуту напрямую, поскольку метод __get__Извините, если я плохо объясняю. Я делаю все возможное. Спасибо!
Подробнее здесь: https://stackoverflow.com/questions/786 ... -metaclass