"""Absfuyu: Core-------------DecoratorVersion: 5.1.0Date updated: 10/03/2025 (dd/mm/yyyy)"""# Module Package# ---------------------------------------------------------------------------__all__=["dummy_decorator","dummy_decorator_with_args","add_subclass_methods_decorator",]# Library# ---------------------------------------------------------------------------fromcollections.abcimportCallablefromfunctoolsimportwrapsfromtypingimportParamSpec,TypeVar,overload# Type# ---------------------------------------------------------------------------P=ParamSpec("P")# Parameter typeR=TypeVar("R")# Return type - Can be anythingT=TypeVar("T",bound=type)# Type type - Can be any subtype of `type`# Decorator# ---------------------------------------------------------------------------@overloaddefdummy_decorator(obj:T)->T:...@overloaddefdummy_decorator(obj:Callable[P,R])->Callable[P,R]:...
[docs]defdummy_decorator(obj:Callable[P,R]|T)->Callable[P,R]|T:""" This is a decorator that does nothing. Normally used as a placeholder """ifisinstance(obj,type):returnobj@wraps(obj)defwrapper(*args:P.args,**kwargs:P.kwargs)->R:returnobj(*args,**kwargs)returnwrapper
[docs]defdummy_decorator_with_args(*args,**kwargs):""" This is a decorator with args and kwargs that does nothing. Normally used as a placeholder """@overloaddefdecorator(obj:T)->T:...@overloaddefdecorator(obj:Callable[P,R])->Callable[P,R]:...defdecorator(obj:Callable[P,R]|T)->Callable[P,R]|T:ifisinstance(obj,type):returnobj@wraps(obj)defwrapper(*args:P.args,**kwargs:P.kwargs)->R:returnobj(*args,**kwargs)returnwrapperreturndecorator
[docs]defadd_subclass_methods_decorator(cls:T)->T:""" Class decorator replace the ``__init_subclass__`` method. This method populates a dictionary with subclass names as keys and their available methods as values. - Create 2 class attributes: ``_METHOD_INCLUDE`` (bool) and ``SUBCLASS_METHODS`` (dict[str, list[str]]) - Automatically add subclass methods to class variable: ``SUBCLASS_METHODS`` - Set class attribute ``_METHOD_INCLUDE`` to ``False`` to exclude from ``SUBCLASS_METHODS`` Example: -------- >>> # Normal behavior >>> @add_subclass_methods_decorator >>> class TestParent: ... >>> class TestChild(TestParent): ... def method1(self): ... >>> TestChild.SUBCLASS_METHODS {'__main__.TestChild': ['method1']} >>> # Hidden from ``SUBCLASS_METHODS`` >>> @add_subclass_methods_decorator >>> class TestParent: ... >>> class TestChildHidden(TestParent): ... _METHOD_INCLUDE = False ... def method1(self): ... >>> TestChildHidden.SUBCLASS_METHODS {} """# Check for classifnotisinstance(cls,type):raiseValueError("Object is not a class")classAutoSubclassMixin:_METHOD_INCLUDE:bool=True# Include in SUBCLASS_METHODSSUBCLASS_METHODS:dict[str,list[str]]={}def__init_subclass__(cls,*args,**kwargs)->None:""" This create a dictionary with: - key (str) : Subclass - value (list[str]): List of available methods """super().__init_subclass__(*args,**kwargs)ifcls._METHOD_INCLUDEandnotany([x.endswith(cls.__name__)forxincls.SUBCLASS_METHODS.keys()]):methods_list:list[str]=[kfork,vincls.__dict__.items()ifcallable(v)]iflen(methods_list)>0:name=f"{cls.__module__}.{cls.__name__}"cls.SUBCLASS_METHODS.update({name:sorted(methods_list)})returntype("AutoSubclass",(AutoSubclassMixin,cls),{})# type: ignore[return-value]