[docs]classDelegateParameter(Parameter):""" The :class:`.DelegateParameter` wraps a given `source` :class:`Parameter`. Setting/getting it results in a set/get of the source parameter with the provided arguments. The reason for using a :class:`DelegateParameter` instead of the source parameter is to provide all the functionality of the Parameter base class without overwriting properties of the source: for example to set a different scaling factor and unit on the :class:`.DelegateParameter` without changing those in the source parameter. The :class:`DelegateParameter` supports changing the `source` :class:`Parameter`. :py:attr:`~gettable`, :py:attr:`~settable` and :py:attr:`snapshot_value` properties automatically follow the source parameter. If source is set to ``None`` :py:attr:`~gettable` and :py:attr:`~settable` will always be ``False``. It is therefore an error to call get and set on a :class:`DelegateParameter` without a `source`. Note that a parameter without a source can be snapshotted correctly. :py:attr:`.unit` and :py:attr:`.label` can either be set when constructing a :class:`DelegateParameter` or inherited from the source :class:`Parameter`. If inherited they will automatically change when changing the source. Otherwise they will remain fixed. Note: DelegateParameter only supports mappings between the :class:`.DelegateParameter` and :class:`.Parameter` that are invertible (e.g. a bijection). It is therefor not allowed to create a :class:`.DelegateParameter` that performs non invertible transforms in its ``get_raw`` method. A DelegateParameter is not registered on the instrument by default. You should pass ``bind_to_instrument=True`` if you want this to be the case. """class_DelegateCache:def__init__(self,parameter:DelegateParameter):self._parameter=parameterself._marked_valid:bool=False@propertydefraw_value(self)->ParamRawDataType:""" raw_value is an attribute that surfaces the raw value from the cache. In the case of a :class:`DelegateParameter` it reflects the value of the cache of the source. Strictly speaking it should represent that value independent of its validity according to the `max_val_age` but in fact it does lose its validity when the maximum value age has been reached. This bug will not be fixed since the `raw_value` property will be removed soon. """ifself._parameter.sourceisNone:raiseTypeError("Cannot get the raw value of a ""DelegateParameter that delegates to None")returnself._parameter.source.cache.get(get_if_invalid=False)@propertydefmax_val_age(self)->float|None:ifself._parameter.sourceisNone:returnNonereturnself._parameter.source.cache.max_val_age@propertydeftimestamp(self)->datetime|None:ifself._parameter.sourceisNone:returnNonereturnself._parameter.source.cache.timestamp@propertydefvalid(self)->bool:ifself._parameter.sourceisNone:returnFalsesource_cache=self._parameter.source.cachereturnsource_cache.validdefinvalidate(self)->None:ifself._parameter.sourceisnotNone:self._parameter.source.cache.invalidate()defget(self,get_if_invalid:bool=True)->ParamDataType:ifself._parameter.sourceisNone:raiseTypeError("Cannot get the cache of a ""DelegateParameter that delegates to None")returnself._parameter._from_raw_value_to_value(self._parameter.source.cache.get(get_if_invalid=get_if_invalid))defset(self,value:ParamDataType)->None:ifself._parameter.sourceisNone:raiseTypeError("Cannot set the cache of a DelegateParameter ""that delegates to None")self._parameter.validate(value)self._parameter.source.cache.set(self._parameter._from_value_to_raw_value(value))def_set_from_raw_value(self,raw_value:ParamRawDataType)->None:ifself._parameter.sourceisNone:raiseTypeError("Cannot set the cache of a DelegateParameter ""that delegates to None")self._parameter.source.cache.set(raw_value)def_update_with(self,*,value:ParamDataType,raw_value:ParamRawDataType,timestamp:datetime|None=None,)->None:""" This method is needed for interface consistency with ``._Cache`` because it is used by ``ParameterBase`` in ``_wrap_get``/``_wrap_set``. Due to the fact that the source parameter already maintains it's own cache and the cache of the delegate parameter mirrors the cache of the source parameter by design, this method is just a noop. """passdef__call__(self)->ParamDataType:returnself.get(get_if_invalid=True)def__init__(self,name:str,source:Parameter|None,*args:Any,**kwargs:Any,):if"bind_to_instrument"notinkwargs.keys():kwargs["bind_to_instrument"]=Falseforcmdin("set_cmd","get_cmd"):ifcmdinkwargs:raiseKeyError(f'It is not allowed to set "{cmd}" of a 'f"DelegateParameter because the one of the "f"source parameter is supposed to be used.")ifsourceisNoneand("initial_cache_value"inkwargsor"initial_value"inkwargs):raiseKeyError("It is not allowed to supply 'initial_value'"" or 'initial_cache_value' ""without a source.")initial_cache_value=kwargs.pop("initial_cache_value",None)self.source=sourcesuper().__init__(name,*args,**kwargs)self.label=kwargs.get("label",None)self.unit=kwargs.get("unit",None)# Hack While we inherit the settable status from the parent parameter# we do allow param.set_to to temporary override _settable in a# context. Here _settable should always be true except when set_to# i.e. _SetParamContext overrides itself._settable=Trueself.cache=self._DelegateCache(self)ifinitial_cache_valueisnotNone:self.cache.set(initial_cache_value)@propertydefsource(self)->Parameter|None:""" The source parameter that this :class:`DelegateParameter` is bound to or ``None`` if this :class:`DelegateParameter` is unbound. :getter: Returns the current source. :setter: Sets the source. """returnself._source@source.setterdefsource(self,source:Parameter|None)->None:self._source:Parameter|None=source@propertydefsnapshot_value(self)->bool:ifself.sourceisNone:returnFalsereturnself.source.snapshot_value@propertydefunit(self)->str:""" The unit of measure. Read from source if not explicitly overwritten. Set to None to disable overwrite. """ifself._unit_overrideisnotNone:returnself._unit_overrideelifself.sourceisnotNone:returnself.source.unitelse:return""@unit.setterdefunit(self,unit:str|None)->None:self._unit_override=unit@propertydeflabel(self)->str:""" Label of the data used for plots etc. Read from source if not explicitly overwritten. Set to None to disable overwrite. """ifself._label_overrideisnotNone:returnself._label_overrideelifself.sourceisnotNone:returnself.source.labelelse:returnself.name@label.setterdeflabel(self,label:str|None)->None:self._label_override=label@propertydefgettable(self)->bool:ifself.sourceisNone:returnFalsereturnself.source.gettable@propertydefsettable(self)->bool:ifself._settableisFalse:returnFalseifself.sourceisNone:returnFalsereturnself.source.settable
[docs]defget_raw(self)->Any:logger=self._get_logger()logger.debug("Calling get on DelegateParameter %s with source %s",self.full_name,self.source,)ifself.sourceisNone:raiseTypeError("Cannot get the value of a DelegateParameter ""that delegates to a None source.")returnself.source.get()
[docs]defset_raw(self,value:Any)->None:logger=self._get_logger()logger.debug("Calling set on DelegateParameter %s with source %s",self.full_name,self.source,)ifself.sourceisNone:raiseTypeError("Cannot set the value of a DelegateParameter ""that delegates to a None source.")self.source(value)
[docs]defvalidate(self,value:ParamDataType)->None:""" Validate the supplied value. If it has a source parameter, validate the value as well with the source validator. Args: value: value to validate Raises: TypeError: If the value is of the wrong type. ValueError: If the value is outside the bounds specified by the validator. """super().validate(value)ifself.sourceisnotNone:self.source.validate(self._from_value_to_raw_value(value))