# Copyright (c) yibocat 2025 All Rights Reserved
# Python: 3.12.7
# Date: 2025/8/18 18:23
# Author: yibow
# Email: yibocat@yeah.net
# Software: AxisFuzzy
"""
Decorators for registering axisfuzzy extension functions.
Provides the `extension` and `batch_extension` decorators which register
callables into the ExtensionRegistry. Registered callables are later injected
into target classes (e.g. ``Fuzznum``, ``Fuzzarray``) or the top-level axisfuzzy
namespace by the injector at library initialization.
Examples
--------
Simple specialized extension registration:
.. code-block:: python
from axisfuzzy.extension import extension
from axisfuzzy.core import Fuzznum
@extension('distance', mtype='qrofn', target_classes=['Fuzznum'])
def qrofn_distance(f1: Fuzznum, f2: Fuzznum, p: int = 2) -> float:
# qrofn-specific implementation
...
"""
from typing import Optional, Union, List, Literal
from .registry import get_registry_extension
[docs]
def extension(name: str,
mtype: Optional[str] = None,
target_classes: Union[str, List[str]] = None,
injection_type: Literal[
'instance_method',
'top_level_function',
'instance_property',
'both'] = 'both',
is_default: bool = False,
priority: int = 0,
**kwargs):
"""
Register an extension function in the ExtensionRegistry.
This decorator simplifies the process of adding new functionalities
to FuzzLab's ``Fuzznum`` and ``Fuzzarray`` objects, or as top-level functions.
It acts as a wrapper around ``ExtensionRegistry.register()``, providing
a declarative way to define extension properties.
Parameters
----------
name : str
Extension name (e.g. ``distance``).
mtype : str or None, optional
Target fuzzy-number type (e.g. ``qrofn``). If None the registration is
considered a general/default implementation.
target_classes : str or list of str or None, optional
Class name or list of class names to inject into (e.g. ``Fuzznum`` or
``["Fuzznum", "Fuzzarray"]``). If None, library conventions are used.
injection_type : {``instance_method``, ``top_level_function``, ``instance_property``, ``both``}, optional
Injection mode. Default is ``both``.
is_default : bool, optional
Whether this registration is a fallback when no mtype-specific
implementation exists. Default is ``False``.
priority : int, optional
Resolution priority when multiple candidates match. Higher values
take precedence. Default is 0.
**kwargs
Additional metadata forwarded to the registry.
Returns
-------
callable
A decorator that accepts the implementation function and registers it.
Examples
--------
Specialized distance for qrofn:
.. code-block:: python
from axisfuzzy.extension import extension
from axisfuzzy.core import Fuzznum
@extension('distance', mtype='qrofn', target_classes=['Fuzznum'])
def qrofn_distance(f1: Fuzznum, f2: Fuzznum, p: int = 2) -> float:
# qrofn-specific implementation
...
Default distance fallback:
.. code-block:: python
from axisfuzzy.extension import extension
from axisfuzzy.core import Fuzznum
@extension('distance', is_default=True, target_classes=['Fuzznum'])
def default_distance(f1: Fuzznum, f2: Fuzznum) -> float:
# generic fallback implementation
...
"""
registry = get_registry_extension()
return registry.register(
name=name,
mtype=mtype,
target_classes=target_classes,
injection_type=injection_type,
is_default=is_default,
priority=priority,
**kwargs
)
[docs]
def batch_extension(registrations: List[dict]):
"""
Decorator to register a single function with multiple extension configurations.
This is useful when a single function needs to serve different roles
or be registered under various conditions (e.g., as a specialized
implementation for one `mtype` and a default for another, or with
different injection types).
Parameters
----------
registrations : list of dict
Each dict supplies keyword arguments for the `extension` decorator,
e.g. ``{'name': 'normalize', 'mtype': 'qrofn', 'target_classes': ['Fuzznum']}``.
Returns
-------
callable
A decorator which registers the decorated function multiple times.
Examples
--------
Registering a function that serves as a specialized 'normalize' for 'qrofn'
and a default 'normalize' for other types:
.. code-block:: python
# In axisfuzzy/fuzzy/qrofs/_func.py
from axisfuzzy.extension import batch_extension
from axisfuzzy.core import Fuzznum
@batch_extension([
{'name': 'normalize', 'mtype': 'qrofn', 'target_classes': ['Fuzznum']},
{'name': 'normalize', 'is_default': True, 'target_classes': ['Fuzznum']}
])
def qrofn_normalize(fuzz: Fuzznum) -> Fuzznum:
# QROFN specific normalization logic
# ...
return fuzz
"""
def decorator(func):
registry = get_registry_extension()
for reg in registrations:
registry.register(**reg)(func)
return func
return decorator