from __future__ import annotations
import functools
from typing import Any, TYPE_CHECKING
import inspect
from magicgui.widgets import EmptyWidget
from magicclass.signature import get_signature, upgrade_signature
if TYPE_CHECKING:
from ..signature import MagicMethodSignature
_PARTIALIZE = {"gui_only": True, "widget_type": EmptyWidget, "visible": False}
[docs]class partial(functools.partial):
"""
Partialize a function and its signature.
This object is similar to ``functools.partial``, but it also update
widget options to build magicgui widget with subset of widgets. More
precisely, partializing ``x=0`` will add option
``x={"gui_only": True, "widget_type": EmptyWidget, "visible": False}``.
Parameters
----------
func : Callable
Callable object to be partialized.
Examples
--------
Suppose you have a magic class.
>>> @magicclass
>>> class A:
>>> def f(self, i: int): ...
You can partialize method ``f``.
>>> ui = A()
>>> ui.append(partial(ui.f, i=1))
"""
__signature__: MagicMethodSignature
def __new__(cls, func, /, *args, **kwargs):
# prepare widget options
options: dict[str, Any] = {}
bound = inspect.signature(func).bind_partial(*args, **kwargs)
for name in bound.arguments.keys():
options[name] = _PARTIALIZE
# construct partial object
self = functools.partial.__new__(cls, func, *args, **kwargs)
self.__signature__ = get_signature(self)
self.__name__ = func.__name__
upgrade_signature(self, gui_options=options)
return self
[docs] def set_options(
self,
text: str | None = None,
**kwargs,
):
"""Set options for the buttons or actions."""
kwargs.update(text=text)
upgrade_signature(self, caller_options=kwargs)
return self
[docs]class partialmethod(functools.partialmethod):
"""
Partialize a method and its signature.
This object is similar to ``functools.partialmethod``, but it also update
widget options to build magicgui widget with subset of widgets. More
precisely, partializing ``x=0`` will add option
``x={"gui_only": True, "widget_type": EmptyWidget, "visible": False}``.
Parameters
----------
func : Callable
Callable object to be partialized.
Examples
--------
>>> @magicclass
>>> class A:
>>> def f(self, i: int): ...
>>> g = partialmethod(f, i=1)
"""
__signature__: MagicMethodSignature
def __init__(self, func, /, *args, **kwargs):
# prepare widget options
options: dict[str, Any] = {}
bound = inspect.signature(func).bind_partial(*args, **kwargs)
for name in bound.arguments.keys():
options[name] = _PARTIALIZE
# construct partial object
super().__init__(func, *args, **kwargs)
self.__signature__ = get_signature(partial(func, *args, **kwargs))
self.__name__ = func.__name__
upgrade_signature(self, gui_options=options)
def __call__(self, *args: Any, **kwargs: Any):
# needed to be defined because magicclass checks callable
raise TypeError("partialmethod object is not callable")
def __set_name__(self, owner, name):
self.__signature__.caller_options.setdefault("text", name.replace("_", " "))
[docs] def set_options(
self,
text: str | None = None,
**kwargs,
):
"""Set options for the buttons or actions."""
kwargs.update(text=text)
upgrade_signature(self, caller_options=kwargs)
return self