# This is supposed to be used in CLI, so the functions contain printing.# ruff: noqa: T201from__future__importannotationsfromtypingimportTYPE_CHECKINGfrom._deviceimportDevice,DeviceFilterfrom._platformimportPlatform,PlatformFilterifTYPE_CHECKING:# pragma: no coverfromcollections.abcimportSequencefrom._apiimportAPI
[docs]defplatforms_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)forplatforminsuitable_platforms:suitable_devices=Device.all_filtered(platform,device_filter)if(quantityisNoneandlen(suitable_devices)>0)or(quantityisnotNoneandlen(suitable_devices)>=quantity):results.append((platform,suitable_devices))returnresults
def_select_devices_interactive(suitable_pds:Sequence[tuple[Platform,Sequence[Device]]],quantity:int|None=1)->list[Device]:iflen(suitable_pds)==1:platform,devices=suitable_pds[0]print(f"Platform: {platform.name}")else:print("Platforms:")forpnum,pdinenumerate(suitable_pds):platform,_=pdprint(f"[{pnum}]: {platform.name}")default_pnum=0selected_pnum=default_pnumprint(f"Choose the platform [{default_pnum}]: ",end="")pnum_input=input()ifpnum_input!="":selected_pnum=int(pnum_input)platform,devices=suitable_pds[selected_pnum]ifquantityisNoneor(quantityisnotNoneandlen(devices)==quantity):selected_devices=list(devices)print(f"Devices: {[device.namefordeviceinselected_devices]}")else:print("Devices:")default_dnums=list(range(quantity))fordnum,deviceinenumerate(devices):print(f"[{dnum}]: {device.name}")default_dnums_str=", ".join(str(dnum)fordnumindefault_dnums)print(f"Choose the device(s), comma-separated [{default_dnums_str}]: ",end="")selected_dnums=default_dnumsdnums_input=input()ifdnums_input!="":selected_dnums=[int(dnum)fordnumindnums_input.split(",")]iflen(selected_dnums)!=quantity:raiseValueError(f"Exactly {quantity} devices must be selected")selected_devices=[devices[dnum]fordnuminselected_dnums]returnselected_devices
[docs]defselect_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)iflen(suitable_pds)==0:quantity_val="any"ifquantityisNoneelsequantityraiseValueError(f"Could not find {quantity_val} devices on a single platform ""matching the given criteria")ifinteractive:return_select_devices_interactive(suitable_pds,quantity=quantity)_,devices=suitable_pds[0]returndevicesifquantityisNoneelsedevices[:quantity]