"""
Absfuyu: Core
-------------
Bases for other features (with library)
Version: 5.1.0
Date updated: 10/03/2025 (dd/mm/yyyy)
"""
# Module Package
# ---------------------------------------------------------------------------
__all__ = [
# Class
"ShowAllMethodsMixinInspectVer",
# Metaclass
"PerformanceTrackingMeta",
# Class decorator
"positive_class_init_args",
]
# Library
# ---------------------------------------------------------------------------
import time
import tracemalloc
from collections.abc import Callable
from functools import wraps
from inspect import getmro, isfunction
from types import MethodType
from typing import Any, ParamSpec, TypeVar
# Type
# ---------------------------------------------------------------------------
P = ParamSpec("P") # Parameter type
T = TypeVar("T", bound=type) # Type type - Can be any subtype of `type`
# R = TypeVar("R") # Return type
# Class
# ---------------------------------------------------------------------------
[docs]
class ShowAllMethodsMixinInspectVer:
[docs]
@classmethod
def show_all_methods(
cls,
include_classmethod: bool = True,
classmethod_indicator: str = "<classmethod>",
) -> dict[str, list[str]]:
result = {}
for base in getmro(cls)[::-1]:
methods = []
# for name, attr in inspect.getmembers(base, predicate=callable):
for name, attr in base.__dict__.items():
if name.startswith("__"):
continue
if isfunction(attr):
methods.append(name)
# if inspect.ismethod(attr):
if isinstance(attr, (classmethod, MethodType)) and include_classmethod:
methods.append(f"{name} {classmethod_indicator}")
if methods:
result[base.__name__] = sorted(methods)
return result
# Metaclass
# ---------------------------------------------------------------------------
# Decorator
# ---------------------------------------------------------------------------
[docs]
def positive_class_init_args(cls: T):
"""
A class decorator that ensures all arguments in the ``__init__()`` method are positive.
"""
# original_init: Callable[P, None] | None = getattr(cls, "__init__", None)
# if original_init is None:
# return cls
try:
original_init: Callable[P, None] = cls.__init__ # type: ignore
except AttributeError:
return cls
@wraps(original_init)
def new_init(self, *args: P.args, **kwargs: P.kwargs):
# Check if all positional arguments are positive
for arg in args:
if isinstance(arg, (int, float)) and arg < 0:
raise ValueError(f"Argument {arg} must be positive")
# Check if all keyword arguments are positive
for key, value in kwargs.items():
if isinstance(value, (int, float)) and value < 0:
raise ValueError(f"Argument {key}={value} must be positive")
# Call the original __init__ method
original_init(self, *args, **kwargs)
# setattr(cls, "__init__", new_init)
cls.__init__ = new_init # type: ignore
return cls