Source code for magicclass.utils

from __future__ import annotations
import inspect
from enum import Enum
from typing import Any, TYPE_CHECKING
from docstring_parser import parse
from qtpy.QtWidgets import QApplication, QMessageBox

if TYPE_CHECKING:
    from magicgui.widgets import FunctionGui

__all__ = ["MessageBoxMode", "show_messagebox", "open_url", "screen_center"]

def iter_members(cls: type, exclude_prefix: str = "__") -> list[str, Any]:
    """
    Iterate over all the members in the order of source code line number. 
    This function is identical to inspect.getmembers except for the order
    of the results. We have to sort the name in the order of line number.
    """    
    mro = (cls,) + inspect.getmro(cls)
    processed = set()
    names: list[str] = list(cls.__dict__.keys())
    try:
        for base in mro:
            for k in base.__dict__.keys():
                if k not in names:
                    names.append(k)
                    
    except AttributeError:
        pass
    
    for key in names:
        try:
            value = getattr(cls, key)
            # handle the duplicate key
            if key in processed:
                raise AttributeError
        except AttributeError:
            for base in mro:
                if key in base.__dict__:
                    value = base.__dict__[key]
                    break
            else:
                continue
        if not key.startswith(exclude_prefix):
            yield key, value
        processed.add(key)
    

def extract_tooltip(obj: Any) -> str:
    if not hasattr(obj, "__doc__"):
        return ""
    
    doc = parse(obj.__doc__)
    if doc.short_description is None:
        return ""
    elif doc.long_description is None:
        return doc.short_description
    else:
        return doc.short_description + "\n" + doc.long_description


def get_signature(func):
    """
    Similar to ``inspect.signature`` but safely returns ``MagicMethodSignature``.
    """    
    if hasattr(func, "__signature__"):
        sig = func.__signature__
    else:
        sig = inspect.signature(func)
    return sig

[docs]class MessageBoxMode(Enum): ERROR = "error" WARNING = "warn" INFO = "info" QUESTION = "question" ABOUT = "about"
_QMESSAGE_MODES = { MessageBoxMode.ERROR: QMessageBox.critical, MessageBoxMode.WARNING: QMessageBox.warning, MessageBoxMode.INFO: QMessageBox.information, MessageBoxMode.QUESTION: QMessageBox.question, MessageBoxMode.ABOUT: QMessageBox.about, }
[docs]def show_messagebox(mode: str | MessageBoxMode = MessageBoxMode.INFO, title: str = None, text: str = None, parent=None ) -> bool: """ Freeze the GUI and open a messagebox dialog. Parameters ---------- mode : str or MessageBoxMode, default is MessageBoxMode.INFO Mode of message box. Must be "error", "warn", "info", "question" or "about". title : str, optional Title of messagebox. text : str, optional Text in messagebox. parent : QWidget, optional Parent widget. Returns ------- bool If "OK" or "Yes" is clicked, return True. Otherwise return False. """ show_dialog = _QMESSAGE_MODES[MessageBoxMode(mode)] result = show_dialog(parent, title, text) return result in (QMessageBox.Ok, QMessageBox.Yes)
[docs]def open_url(link: str) -> None: """ Open the link with the default browser. Parameters ---------- link : str Link to the home page. """ from qtpy.QtGui import QDesktopServices from qtpy.QtCore import QUrl QDesktopServices.openUrl(QUrl(link))
def to_clipboard(obj: Any) -> None: """ Copy an object of any type to the clipboard. You can copy text, ndarray as an image or data frame as a table data. Parameters ---------- obj : Any Object to be copied. """ from qtpy.QtGui import QGuiApplication, QImage import numpy as np import pandas as pd clipboard = QGuiApplication.clipboard() if isinstance(obj, str): clipboard.setText(obj) elif isinstance(obj, np.ndarray): clipboard.setImage(QImage(obj)) elif isinstance(obj, pd.DataFrame): clipboard.setText(obj.to_csv()) else: clipboard.setText(str(obj))
[docs]def screen_center(): """ Get the center coordinate of the screen. """ return QApplication.desktop().screen().rect().center()