Source code for app.util.mixins.named

# SPDX-License-Identifier: GPLv3
# Copyright © 2025 pygaindalf Rui Pinheiro

from typing import Protocol, runtime_checkable

from . import shorten_name
from typing import override, ClassVar
from abc import ABCMeta, abstractmethod


# MARK: Protocols
[docs] @runtime_checkable class NamedProtocol(Protocol): @property def instance_name(self) -> str | None: ...
[docs] @runtime_checkable class FinalNamedProtocol(NamedProtocol, Protocol): @property def final_instance_name(self) -> str: ...
[docs] @runtime_checkable class NamedMutableProtocol(NamedProtocol, Protocol): @property @override def instance_name(self) -> str | None: ... @instance_name.setter def instance_name(self, new_name: str | None) -> None: ...
# MARK: Minimal Mixin for Named Classes
[docs] class NamedMixinMinimal(metaclass=ABCMeta): @property def final_instance_name(self): if (name := self.instance_name) is None: # pyright: ignore[reportAttributeAccessIssue] as this mixin must only be used when instance_parent is accessible name = self.get_default_name() return name @property def instance_short_name(self) -> str | None: """ Get a shortened version of the instance name. Returns: str: The shortened instance name. """ name = self.instance_name # pyright: ignore[reportAttributeAccessIssue] as this mixin must only be used when instance_parent is accessible return shorten_name(name) if name is not None else None @property def final_instance_short_name(self) -> str: return shorten_name(self.final_instance_name)
[docs] @classmethod def get_default_name(cls) -> str: """ Get the default name for logging. Returns: str: The default name. """ name = getattr(cls, '__name__', None) if name is None: raise ValueError("Could not determine default name") return name
@property def __repr_name(self) -> str: """ Get the name to use in __repr__ output. Returns: str: The name for __repr__. """ nm = self.final_instance_name cnm = self.__class__.__name__ if cnm in nm: return nm else: return f"{cnm}:{nm}" @override def __repr__(self) -> str: """ Get the string representation of the instance. Returns: str: The string representation. """ return f"<{self.__repr_name}>" @property def __str_name(self) -> str: """ Get the string name for the instance. Returns: str: The string name. """ nm = self.final_instance_name cnm = self.__class__.__name__ if nm == cnm: return nm else: return f"{shorten_name(self.__class__.__name__)} {nm}" @override def __str__(self) -> str: """ Get the string representation of the instance. Returns: str: The string representation. """ return f"<{self.__str_name}>"
# MARK: Mixin for Named Classes
[docs] class NamedMixin(NamedMixinMinimal): """ Mixin that adds a name to a class instance. Provides instance_name and related properties for identification, logging, and display purposes. Used for configuration, logging, and user-facing objects in pygaindalf. """ """ Attribute name used to store the instance name This is used to allow base classes to customise this without needing to override the instance_name property """ NAMED_MIXIN_ATTRIBUTE : ClassVar[str] = '__name'
[docs] def __init__(self, *args, instance_name:str|None=None, **kwargs): """ Initialize the mixin and set the instance name. Args: instance_name (Optional[str]): Optional name for the instance. *args: Additional positional arguments for superclasses. **kwargs: Additional keyword arguments for superclasses. """ super().__init__(*args, **kwargs) self.instance_name = instance_name
@property def instance_name(self) -> str | None: """ Get the instance name, or class name if not set. Returns: str: The instance name. """ return getattr(self, self.__class__.NAMED_MIXIN_ATTRIBUTE, None) @instance_name.setter def instance_name(self, new_name : str | None) -> None: """ Set the instance name. Args: new_name (str): The new name to set. """ setattr(self, self.__class__.NAMED_MIXIN_ATTRIBUTE, new_name) from .loggable import LoggableMixin if isinstance(self, LoggableMixin): self._reset_log_cache() def __set_name__(self, owner : type, name : str): """ Set the instance name based on the attribute name and owner """ if self.instance_name is None: from . import HierarchicalProtocol, NamedProtocol if isinstance(self, HierarchicalProtocol): if isinstance(owner, NamedProtocol): owner_name = owner.instance_name elif hasattr(owner, '__name__'): owner_name = owner.__name__ else: owner_name = owner.__class__.__name__ self.instance_name = f"{owner_name}.{name}" else: self.instance_name = name