Skip to content

available

Full documentation pages are generated for docstring reference only and may contain symbols imported from other modules. Imported symbols are not distinguished from locally defined symbols and will appear in any module that they are imported into. For better information on where symbols should be imported from, review the sourcecode on the github.

FoSpy.ui.available

AVAILABLE_UIS module-attribute

AVAILABLE_UIS = [
    ui
    for ui, req in (_UI_REQUIREMENTS.items())
    if _check_requirement(req)
]

_UI_REQUIREMENTS module-attribute

_UI_REQUIREMENTS = {
    "pyqtgraph": (
        "pyqtgraph",
        ["PySide6", "PyQt6", "PySide2", "PyQt5"],
    ),
    "app": ("PySide6", "qdarktheme"),
    "native": ("tkinter", "matplotlib"),
}

UINotAvailable

Bases: Exception

Source code in FoSpy/ui/available.py
class UINotAvailable(Exception):
    pass

_check_requirement

_check_requirement(req)
Source code in FoSpy/ui/available.py
def _check_requirement(req:str|list|tuple) -> bool:
    if isinstance(req, str):
        return _is_package_installed(req)

    if isinstance(req, tuple):
        return all(_check_requirement(dep) for dep in req)

    if isinstance(req, list):
        return any(_check_requirement(dep) for dep in req)

    # shouldn't get here
    raise ValueError(f"Unknown logic structure for requirement: {type(req)}. "
                     "Expected str, list, or tuple.")

_is_package_installed

_is_package_installed(package_name)
Source code in FoSpy/ui/available.py
def _is_package_installed(package_name:str) -> bool:
    return imp_util.find_spec(package_name) is not None

_summarize_reqs

_summarize_reqs(req, indent=0)
Source code in FoSpy/ui/available.py
def _summarize_reqs(req:str|list|tuple, indent=0):
    txt = f"{'  '*indent}- [{'OK' if _check_requirement(req) else 'XX'}] "

    if isinstance(req, str):
        return txt + req

    if isinstance(req, (tuple, list)):
        txt += "ALL OF:\n" if isinstance(req, tuple) else "ONE OF:\n"
        return txt + "\n".join([_summarize_reqs(dep, indent+1) for dep in req])

    # shouldn't get here
    raise ValueError(f"Unknown logic structure for requirement: {type(req)}. "
                     "Expected str, list, or tuple.")

discover_ui_options

discover_ui_options(target)
Source code in FoSpy/ui/available.py
def discover_ui_options(target:str|ModuleType) -> dict[str, ModuleType]:
    ui_opts = {}

    base_package = target.__name__ if isinstance(target, ModuleType) else str(target)

    for ui_name in get_available_uis():
        absolute_name = f"{base_package}.{ui_name}"

        spec = imp_util.find_spec(absolute_name)
        if spec is not None:
            ui_opts[ui_name] = import_module(absolute_name)

    return ui_opts

get_available_uis

get_available_uis()
Source code in FoSpy/ui/available.py
def get_available_uis():
    return AVAILABLE_UIS

get_valid_ui

get_valid_ui(ui_name=None, options=None)
Source code in FoSpy/ui/available.py
def get_valid_ui(ui_name=None, options=None):
    from ..config import values as cfg
    from warnings import warn


    ui_name = ui_name or cfg.get("ui.default", "native")
    if options is None:
        options = _UI_REQUIREMENTS.keys()
    else:
        options = [o.lower() for o in options]

    if ui_name.lower() not in options:
        new_ui = options[0]



        warn_txt = (f"\n\nThe '{ui_name}' backend is not available for the requested context "
                    f"(See dependency summary below). Attempting to use '{new_ui}' instead.\n\n"
                    f"===== DEPENDENCIES FOR '{ui_name.upper()}' UI =====\n")
        warn_txt += _summarize_reqs(_UI_REQUIREMENTS[ui_name])

        warn(warn_txt, RuntimeWarning)

        ui_name = new_ui

    available_options = [o for o in options if o in AVAILABLE_UIS]
    installable_options = {o: _UI_REQUIREMENTS[o] for o in options if o in _UI_REQUIREMENTS}

    try:
        validate_ui(ui_name)
        return ui_name
    except UINotAvailable as e:
        if len(available_options) > 0:
            fallback = available_options[0]

            warn(f"\n\nThe '{ui_name}' UI backend is not available (exception below). "
                    f"Using the first available UI,'{fallback}', instead.\n\n{e}", RuntimeWarning)

            return fallback
        # proceed to raise if no fallback is available

    # Only reached on UINotAvailable and no fallback 
    summary = (f"The '{ui_name}' UI backend is not available. There are no "
                "available UIs to fallback to.\n"
                "Refer to the dependency summaries below and install the "
                "missing dependencies for your UI of choice.\nNOTE: The "
                "'native' UI is the most lightweight and is recommended for "
                "users looking for a simple UI or who don't use the UI "
                "often.\n\n")

    for ui, req in installable_options.items():
        summary += f"===== DEPENDENCIES FOR '{ui.upper()}' UI =====\n"
        summary += _summarize_reqs(req)
        summary += "\n\n"

    raise UINotAvailable(summary)

is_ui_available

is_ui_available(ui_name)
Source code in FoSpy/ui/available.py
def is_ui_available(ui_name):
    return ui_name.lower() in AVAILABLE_UIS

validate_ui

validate_ui(ui_name)
Source code in FoSpy/ui/available.py
def validate_ui(ui_name):
    ui_lower = ui_name.lower()
    if ui_lower not in _UI_REQUIREMENTS:
        valids = ", ".join(_UI_REQUIREMENTS.keys())
        raise UINotAvailable(f"UI '{ui_name}' is not a valid UI. Valid options are: {valids}.")

    if ui_lower not in AVAILABLE_UIS:
        raise UINotAvailable(
            f"The '{ui_name}' UI backend cannot be used because it is missing dependencies. "
            "Refer to the summary below and install the missing dependencies to use this UI.\n\n"
            f"{_summarize_reqs(_UI_REQUIREMENTS[ui_lower])}"
        )