Исходный код EJIO.utils.interface.mutable_static_class
## /utils/interface/mutable_static_class.py
from typing import Any, NoReturn, Callable
from .static_class import StaticClassMeta
__all__ = [
'MutableStaticMeta',
'static_property',
]
[документация]
class static_property:
"""
Кастомный маркер-дескриптор для объявления вычисляемых свойств
внутри изменяемых статических структур.
"""
__slots__ = ('_func',)
def __init__(self, func: Callable[..., Any]) -> None:
self._func = func
self.__doc__ = func.__doc__ #type ignore
def __get__(self, instance: Any, owner: Any) -> Any:
# Если обращение идет от имени класса, передаем контекст класса в функцию
return self._func(owner)
[документация]
class MutableStaticMeta(StaticClassMeta):
"""
Метакласс для изменяемых статических структур конфигурации.
Запрещает создание экземпляров, но разрешает чтение функций класса
как вычисляемых свойств (property) без круглых скобок.
"""
__slots__ = ()
def __delattr__(cls, name: str) -> NoReturn:
"""
Запрещает удаление атрибутов из статическрй структуры.
:param name: Имя удаляемого атрибута.
"""
raise AttributeError(f"Cannot delete configuration property '{name}' from static structure.")
def __getattribute__(cls, name: str) -> Any:
"""
Перехватывает чтение любых атрибутов. Если атрибут является вызываемым
методом класса, автоматически выполняет его и возвращает результат.
:param name: Имя запрашиваемого атрибута.
:return: Значение запрашиваемого атрибута, либо выполненную функцию,
если атрибут - это функция.
"""
# 1. Защита от бесконечной рекурсии: пропускаем дандеры и служебные маркеры
if name.startswith('__') and name.endswith('__'):
return super().__getattribute__(name)
# 2. Проверяем явные декларации через декораторы в словаре класса
if name in cls.__dict__:
raw_attr = cls.__dict__[name]
if isinstance(raw_attr, static_property):
return raw_attr.__get__(None, cls)
# 3. Обрабатываем обычные методы на уровне статического класса
return super().__getattribute__(name)