Source code for grunnur._device_discovery

# This is supposed to be used in CLI, so the functions contain printing.
# ruff: noqa: T201

from __future__ import annotations

from typing import TYPE_CHECKING

from ._device import Device, DeviceFilter
from ._platform import Platform, PlatformFilter

if TYPE_CHECKING:  # pragma: no cover
    from collections.abc import Sequence

    from ._api import API


[docs] def platforms_and_devices_by_mask( api: API, quantity: int | None = 1, device_filter: DeviceFilter | None = None, platform_filter: PlatformFilter | None = None, ) -> list[tuple[Platform, list[Device]]]: """ Returns all tuples (platform, list of devices) where the platform name and device names satisfy the given criteria, and there are at least ``quantity`` devices in the list. """ results = [] suitable_platforms = Platform.all_filtered(api, platform_filter) for platform in suitable_platforms: suitable_devices = Device.all_filtered(platform, device_filter) if (quantity is None and len(suitable_devices) > 0) or ( quantity is not None and len(suitable_devices) >= quantity ): results.append((platform, suitable_devices)) return results
def _select_devices_interactive( suitable_pds: Sequence[tuple[Platform, Sequence[Device]]], quantity: int | None = 1 ) -> list[Device]: if len(suitable_pds) == 1: platform, devices = suitable_pds[0] print(f"Platform: {platform.name}") else: print("Platforms:") for pnum, pd in enumerate(suitable_pds): platform, _ = pd print(f"[{pnum}]: {platform.name}") default_pnum = 0 selected_pnum = default_pnum print(f"Choose the platform [{default_pnum}]: ", end="") pnum_input = input() if pnum_input != "": selected_pnum = int(pnum_input) platform, devices = suitable_pds[selected_pnum] if quantity is None or (quantity is not None and len(devices) == quantity): selected_devices = list(devices) print(f"Devices: {[device.name for device in selected_devices]}") else: print("Devices:") default_dnums = list(range(quantity)) for dnum, device in enumerate(devices): print(f"[{dnum}]: {device.name}") default_dnums_str = ", ".join(str(dnum) for dnum in default_dnums) print(f"Choose the device(s), comma-separated [{default_dnums_str}]: ", end="") selected_dnums = default_dnums dnums_input = input() if dnums_input != "": selected_dnums = [int(dnum) for dnum in dnums_input.split(",")] if len(selected_dnums) != quantity: raise ValueError(f"Exactly {quantity} devices must be selected") selected_devices = [devices[dnum] for dnum in selected_dnums] return selected_devices
[docs] def select_devices( api: API, *, interactive: bool = False, quantity: int | None = 1, device_filter: DeviceFilter | None = None, platform_filter: PlatformFilter | None = None, ) -> list[Device]: """ Using the results from :py:func:`platforms_and_devices_by_mask`, either lets the user select the devices (from the ones matching the criteria) interactively, or takes the first matching list of ``quantity`` devices. :param interactive: if ``True``, shows a dialog to select the devices. If ``False``, selects the first matching ones. :param quantity: passed to :py:func:`platforms_and_devices_by_mask`. :param device_filters: passed to :py:func:`platforms_and_devices_by_mask`. """ suitable_pds = platforms_and_devices_by_mask( api, quantity, device_filter=device_filter, platform_filter=platform_filter ) if len(suitable_pds) == 0: quantity_val = "any" if quantity is None else quantity raise ValueError( f"Could not find {quantity_val} devices on a single platform " "matching the given criteria" ) if interactive: return _select_devices_interactive(suitable_pds, quantity=quantity) _, devices = suitable_pds[0] return devices if quantity is None else devices[:quantity]