/qcodes/instrument/delegate/grouped_parameter.py

https://github.com/QCoDeS/Qcodes · Python · 234 lines · 161 code · 20 blank · 53 comment · 24 complexity · 7887f5b203965ee13fec538fbfe8f79f MD5 · raw file

  1. from collections import OrderedDict, namedtuple
  2. from typing import (
  3. TYPE_CHECKING,
  4. Any,
  5. Callable,
  6. Dict,
  7. Iterable,
  8. Mapping,
  9. Optional,
  10. Sequence,
  11. Tuple,
  12. Union,
  13. )
  14. from qcodes.instrument.group_parameter import Group, GroupParameter
  15. from qcodes.instrument.parameter import (
  16. DelegateParameter,
  17. ParamDataType,
  18. Parameter,
  19. ParamRawDataType,
  20. _BaseParameter,
  21. )
  22. if TYPE_CHECKING:
  23. from qcodes.instrument.base import InstrumentBase
  24. import logging
  25. _log = logging.getLogger(__name__)
  26. class DelegateGroupParameter(DelegateParameter, GroupParameter):
  27. def __init__(
  28. self,
  29. name: str,
  30. source: Optional[Parameter],
  31. instrument: Optional['InstrumentBase'] = None,
  32. initial_value: Union[float, str, None] = None,
  33. **kwargs: Any,
  34. ) -> None:
  35. super().__init__(
  36. name=name,
  37. source=source,
  38. instrument=instrument,
  39. initial_value=initial_value,
  40. **kwargs,
  41. )
  42. class DelegateGroup(Group):
  43. """The DelegateGroup combines :class:`.DelegateParameter` s that
  44. are to be gotten or set using one :class:`.GroupedParameter`.
  45. Each :class:`.DelegateParameter` maps to one source parameter
  46. that is individually set or gotten on an instrument. These
  47. parameters can originate from the same or different instruments.
  48. The class :class:`.DelegateGroup` is used within the
  49. :class:`GroupedParameter` class in order to get and set the
  50. :class:`.DelegateParameter` s either via their default get and set
  51. methods or via a custom get or set method.
  52. The value to be set can be passed to the set method either via a
  53. dictionary, where the keys are the names of the
  54. :class:`.DelegateParameter` s contained in the :class:`DelegateGroup`,
  55. or a single value, if a custom setter is defined or if the group
  56. only contains a single :class:`.DelegateParameter`.
  57. The value returned by the get method is passed through a formatter.
  58. By default, the formatter returns the :class:`.DelegateParameter`
  59. values in a namedtuple, where the keys are the names of the
  60. :class:`.DelegateParameter` s. In the special case where the
  61. :class:`.DelegateGroup` only contains one :class:`.DelegateParameter`,
  62. the formatter simply returns the individual value. Optionally,
  63. the formatter can be customized and specified via the constructor.
  64. The formatter takes as input the values of the :class:`.DelegateParameter` s
  65. as positional arguments in the order at which the
  66. :class:`.DelegateParameter` s are specified.
  67. Args:
  68. name: Name of the DelegateGroup
  69. parameters: DelegateParameters to group together
  70. parameter_names: Optional names of parameters, defaults to the
  71. parameter `name` attributes
  72. setter: Optional function to call for setting the grouped parameters,
  73. should take one argument `value`. Defaults to set_parameters(),
  74. which sets each parameter using its .set() method.
  75. getter: Optional function to call for getting the grouped parameters.
  76. Defaults to .get_parameters(), which runs the get() method for each
  77. parameter.
  78. formatter: Optional formatter for value returned by get_parameters(),
  79. defaults to a namedtuple with the parameter names as keys.
  80. """
  81. def __init__(
  82. self,
  83. name: str,
  84. parameters: Sequence[DelegateGroupParameter],
  85. parameter_names: Optional[Iterable[str]] = None,
  86. setter: Optional[Callable[..., Any]] = None,
  87. getter: Optional[Callable[..., Any]] = None,
  88. formatter: Optional[Callable[..., Any]] = None,
  89. **kwargs: Any
  90. ):
  91. super().__init__(
  92. parameters=parameters,
  93. single_instrument=False,
  94. **kwargs
  95. )
  96. self.name = name
  97. self._parameter_names = parameter_names or [
  98. _e.name for _e in parameters
  99. ]
  100. self._set_fn = setter
  101. self._get_fn = getter
  102. self._params = parameters
  103. self._parameters = OrderedDict(zip(self._parameter_names, parameters))
  104. if formatter is None and len(parameters) == 1:
  105. self._formatter = lambda result: result
  106. elif formatter is None:
  107. self._formatter = self._namedtuple
  108. else:
  109. self._formatter = formatter
  110. def _namedtuple(self, *args: Any, **kwargs: Any) -> Tuple[Any, ...]:
  111. return namedtuple(self.name, self._parameter_names)(*args, **kwargs)
  112. def set(self, value: Union[ParamDataType, Mapping[str, ParamDataType]]) -> None:
  113. if self._set_fn is not None:
  114. self._set_fn(value)
  115. else:
  116. if not isinstance(value, dict):
  117. value = {
  118. name: value for name in self._parameter_names
  119. }
  120. self.set_parameters(value)
  121. def get(self) -> Any:
  122. if self._get_fn is not None:
  123. return self._get_fn()
  124. else:
  125. return self.get_parameters()
  126. def get_parameters(self) -> Any:
  127. return self._formatter(*(_p.get() for _p in self.parameters.values()))
  128. def _set_from_dict(self, calling_dict: Mapping[str, ParamRawDataType]) -> None:
  129. for name, p in list(self.parameters.items()):
  130. p.set(calling_dict[name])
  131. @property
  132. def source_parameters(self) -> Tuple[Optional[Parameter], ...]:
  133. """Get source parameters of each DelegateParameter"""
  134. return tuple(p.source for p in self._params)
  135. class GroupedParameter(_BaseParameter):
  136. """
  137. The GroupedParameter wraps one or more :class:`.DelegateParameter` s,
  138. such that those parameters can be accessed as if they were one
  139. parameter.
  140. The :class:`GroupedParameter` uses a :class:`DelegateGroup` to keep
  141. track of the :class:`.DelegateParameter` s. Mainly, this class is a
  142. thin wrapper around the :class:`DelegateGroup`, and mainly exists
  143. in order to allow for it to be used as a :class:`_BaseParameter`.
  144. This class can be seen as the opposite of a :class:`GroupParameter`,
  145. which is a class to create parameters that are set with a single get
  146. and set string command on *the same* instrument but need to be accessed
  147. separately. In contrast, the :class:`GroupedParameter` allows grouped
  148. access to parameters that are normally separate, and can be associated
  149. with *different* instruments.
  150. Args:
  151. name: Grouped parameter name.
  152. group: Group that contains the target parameter(s).
  153. unit: The unit of measure. Use ``''`` for unitless.
  154. label: Optional label, defaults to parameter name.
  155. default set method(s).
  156. """
  157. def __init__(
  158. self,
  159. name: str,
  160. group: DelegateGroup,
  161. unit: Optional[str] = None,
  162. label: Optional[str] = None,
  163. **kwargs: Any
  164. ):
  165. super().__init__(name, **kwargs)
  166. self.label = name if label is None else label
  167. self.unit = unit if unit is not None else ''
  168. self._group = group
  169. @property
  170. def group(self) -> 'DelegateGroup':
  171. """
  172. The group that contains the target parameters.
  173. """
  174. return self._group
  175. @property
  176. def parameters(self) -> Dict[str, GroupParameter]:
  177. """Get delegate parameters wrapped by this GroupedParameter"""
  178. return self.group.parameters
  179. @property
  180. def source_parameters(self) -> Tuple[Optional[Parameter], ...]:
  181. """Get source parameters of each DelegateParameter"""
  182. return self.group.source_parameters
  183. def get_raw(self) -> Union[ParamDataType, Mapping[str, ParamDataType]]:
  184. """Get parameter raw value"""
  185. return self.group.get_parameters()
  186. def set_raw(self, value: Union[ParamDataType, Mapping[str, ParamDataType]]) -> None:
  187. """Set parameter raw value
  188. Args:
  189. value: Parameter value to set
  190. Returns:
  191. float: Returns the parameter value
  192. """
  193. self.group.set(value)
  194. def __repr__(self) -> str:
  195. output = f"GroupedParameter(name={self.name}"
  196. if self.source_parameters:
  197. source_parameters = ", ".join(str(_) for _ in self.source_parameters)
  198. output += f", source_parameters=({source_parameters})"
  199. output += ")"
  200. return output