We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
GroupParameter initial_value cannot be set
Here's a MWE:
```py
from qcodes.instrument.group_parameter import GroupParameter, Group
from qcodes import Instrument

class MyInstrument(Instrument):
    def __init__(self, name, *args, **kwargs):
        super().__init__(name, *args, **kwargs)

        self.add_parameter(name="foo",
                           initial_value=42,
                           parameter_class=GroupParameter
                          )

        self.group = Group([self.foo])

instr = MyInstrument("test")
```

### Expected behaviour
The instrument should have the GroupParameter with the given initial value.

### Actual behaviour
Raises `RuntimeError("Trying to set Group value but no  group defined")`.

### Proposed fix
The `GroupParameter` should defer setting the initial value until it has been added to the group. One way of doing it would be to add something like the following to `GroupParameter.__init__`, before the `super().__init__` call:
```py
if "initial_value" in kwargs:
    self._initial_value = kwargs["initial_value"]
    kwargs["initial_value"] = None
```
and then adding a `GroupParameter.add_to_group` method where the value is actually set, and calling that instead of just setting `parameter.group = self` in `Group.__init__`. I'm not 100% sure if this is the right way to do it.

### System
**qcodes branch**: master

**qcodes commit**: c7eef82d9ab68afb3546fb3c736f2d5b2ff02a14


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `qcodes/instrument/group_parameter.py`
Content:
```
1 """
2 This module implements a :class:`.Group` intended to hold multiple
3 parameters that are to be gotten and set by the same command. The parameters
4 should be of type :class:`GroupParameter`
5 """
6 
7 
8 from collections import OrderedDict
9 from typing import List, Union, Callable, Dict, Any, Optional
10 
11 from qcodes.instrument.parameter import Parameter
12 from qcodes import Instrument
13 
14 
15 class GroupParameter(Parameter):
16     """
17     Group parameter is a :class:`.Parameter`, whose value can be set or get
18     only with other group parameters. This happens when an instrument
19     has commands which set and get more than one parameter per call.
20 
21     The ``set_raw`` method of a group parameter forwards the call to the
22     group, and the group then makes sure that the values of other parameters
23     within the group are left unchanged. The ``get_raw`` method of a group
24     parameter also forwards the call to the group, and the group makes sure
25     that the command output is parsed correctly, and the value of the
26     parameter of interest is returned.
27 
28     After initialization, the group parameters need to be added to a group.
29     See :class:`.Group` for more information.
30 
31     Args:
32         name: Name of the parameter.
33         instrument: Instrument that this parameter belongs to; this
34               instrument is used by the group to call its get and set commands.
35 
36         **kwargs: All kwargs used by the :class:`.Parameter` class, except
37              ``set_cmd`` and ``get_cmd``.
38     """
39 
40     def __init__(self,
41                  name: str,
42                  instrument: Optional['Instrument'] = None,
43                  **kwargs
44                  ) -> None:
45 
46         if "set_cmd" in kwargs or "get_cmd" in kwargs:
47             raise ValueError("A GroupParameter does not use 'set_cmd' or "
48                              "'get_cmd' kwarg")
49 
50         self.group: Union[Group, None] = None
51         super().__init__(name, instrument=instrument, **kwargs)
52 
53         self.set = self._wrap_set(self.set_raw)
54 
55         self.get_raw = lambda result=None: result if result is not None \
56             else self._get_raw_value()
57 
58         self.get = self._wrap_get(self.get_raw)
59 
60     def _get_raw_value(self) -> Any:
61         if self.group is None:
62             raise RuntimeError("Trying to get Group value but no "
63                                "group defined")
64         self.group.update()
65         return self.raw_value
66 
67     def set_raw(self, value: Any) -> None:
68         if self.group is None:
69             raise RuntimeError("Trying to set Group value but no "
70                                "group defined")
71         self.group.set(self, value)
72 
73 
74 class Group:
75     """
76     The group combines :class:`.GroupParameter` s that are to be gotten or set
77     via the same command. The command has to be a string, for example,
78     a VISA command.
79 
80     The :class:`Group`'s methods are used within :class:`GroupParameter` in
81     order to properly implement setting and getting of a single parameter in
82     the situation where one command sets or gets more than one parameter.
83 
84     The command used for setting values of parameters has to be a format
85     string which contains the names of the parameters the group has been
86     initialized with. For example, if a command has syntax ``CMD a_value,
87     b_value``, where ``a_value`` and ``b_value`` are values of two parameters
88     with names ``a`` and ``b``, then the command string has to be ``CMD {a},
89     {b}``, and the group has to be initialized with two ``GroupParameter`` s
90     ``a_param`` and ``b_param``, where ``a_param.name=="a"`` and
91     ``b_param.name=="b"``.
92 
93     **Note** that by default, it is assumed that the command used for getting
94     values returns a comma-separated list of values of parameters, and their
95     order corresponds to the order of :class:`.GroupParameter` s in the list
96     that is passed to the :class:`Group`'s constructor. Through keyword
97     arguments of the :class:`Group`'s constructor, it is possible to change
98     the separator, and even the parser of the output of the get command.
99 
100     The get and set commands are called via the instrument that the first
101     parameter belongs to. It is assumed that all the parameters within the
102     group belong to the same instrument.
103 
104     Example:
105 
106         ::
107 
108             class InstrumentWithGroupParameters(VisaInstrument):
109                 def __init__(self, name, address, **kwargs):
110                     super().__init__(name, address, **kwargs)
111 
112                     ...
113 
114                     # Here is how group of group parameters is defined for
115                     # a simple case of an example "SGP" command that sets and gets
116                     # values of "enabled" and "gain" parameters (it is assumed that
117                     # "SGP?" returns the parameter values as comma-separated list
118                     # "enabled_value,gain_value")
119                     self.add_parameter('enabled',
120                                        label='Enabled',
121                                        val_mapping={True: 1, False: 0},
122                                        parameter_class=GroupParameter)
123                     self.add_parameter('gain',
124                                        label='Some gain value',
125                                        get_parser=float,
126                                        parameter_class=GroupParameter)
127                     self.output_group = Group([self.enabled, self.gain],
128                                               set_cmd='SGP {enabled}, {gain}',
129                                               get_cmd='SGP?')
130 
131                     ...
132 
133     Args:
134         parameters: a list of :class:`.GroupParameter` instances which have
135             to be gotten  and set via the same command; the order of
136             parameters in the list should correspond to the order of the
137             values returned by the ``get_cmd``.
138         set_cmd: Format string of the command that is used for setting the
139             valueS of the parameters; for example, ``CMD {a}, {b}``.
140         get_cmd: String of the command that is used for getting the values
141             of the parameters; for example, ``CMD?``.
142         separator: A separator that is used when parsing the output of the
143             ``get_cmd`` in order to obtain the values of the parameters; it
144             is ignored in case a custom ``get_parser`` is used.
145         get_parser: A callable with a single string argument that is used to
146             parse the output of the ``get_cmd``; the callable has to return a
147             dictionary where parameter names are keys, and the values are the
148             values (as directly obtained from the output of the get command;
149             note that parsers within the parameters will take care of
150             individual parsing of their values).
151     """
152     def __init__(self,
153                  parameters: List[GroupParameter],
154                  set_cmd: str = None,
155                  get_cmd: str = None,
156                  get_parser: Union[Callable[[str],
157                                             Dict[str, Any]], None] = None,
158                  separator: str = ','
159                  ) -> None:
160         self.parameters = OrderedDict((p.name, p) for p in parameters)
161 
162         for p in parameters:
163             p.group = self
164 
165         if len(set([p.root_instrument for p in parameters])) > 1:
166             raise ValueError(
167                 "All parameters should belong to the same instrument")
168 
169         self.instrument = parameters[0].root_instrument
170 
171         self.set_cmd = set_cmd
172         self.get_cmd = get_cmd
173 
174         if get_parser:
175             self.get_parser = get_parser
176         else:
177             self.get_parser = self._separator_parser(separator)
178 
179     def _separator_parser(self, separator: str
180                           ) -> Callable[[str], Dict[str, Any]]:
181         """A default separator-based string parser"""
182         def parser(ret_str: str) -> Dict[str, Any]:
183             keys = self.parameters.keys()
184             values = ret_str.split(separator)
185             return dict(zip(keys, values))
186 
187         return parser
188 
189     def set(self, set_parameter: GroupParameter, value: Any):
190         """
191         Sets the value of the given parameter within a group to the given
192         value by calling the ``set_cmd``.
193 
194         Args:
195             set_parameter: The parameter within the group to set.
196             value: The new value for this parameter.
197         """
198         if any((p.get_latest() is None) for p in self.parameters.values()):
199             self.update()
200         calling_dict = {name: p.raw_value
201                         for name, p in self.parameters.items()}
202         calling_dict[set_parameter.name] = value
203         if self.set_cmd is None:
204             raise RuntimeError("Calling set but no `set_cmd` defined")
205         command_str = self.set_cmd.format(**calling_dict)
206         if self.instrument is None:
207             raise RuntimeError("Trying to set GroupParameter not attached "
208                                "to any instrument.")
209         self.instrument.write(command_str)
210 
211     def update(self):
212         """
213         Update the values of all the parameters within the group by calling
214         the ``get_cmd``.
215         """
216         ret = self.get_parser(self.instrument.ask(self.get_cmd))
217         for name, p in list(self.parameters.items()):
218             p.get(result=ret[name])
219
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/qcodes/instrument/group_parameter.py b/qcodes/instrument/group_parameter.py
--- a/qcodes/instrument/group_parameter.py
+++ b/qcodes/instrument/group_parameter.py
@@ -30,8 +30,11 @@
 
     Args:
         name: Name of the parameter.
-        instrument: Instrument that this parameter belongs to; this
-              instrument is used by the group to call its get and set commands.
+        instrument: Instrument that this parameter belongs to; this instrument
+            is used by the group to call its get and set commands.
+        initial_value: Initial value of the parameter. Note that either none or
+            all of the parameters in a :class:`.Group` should have an initial
+            value.
 
         **kwargs: All kwargs used by the :class:`.Parameter` class, except
              ``set_cmd`` and ``get_cmd``.
@@ -40,6 +43,7 @@
     def __init__(self,
                  name: str,
                  instrument: Optional['Instrument'] = None,
+                 initial_value: Union[float, int, str, None] = None,
                  **kwargs
                  ) -> None:
 
@@ -48,6 +52,7 @@
                              "'get_cmd' kwarg")
 
         self.group: Union[Group, None] = None
+        self._initial_value = initial_value
         super().__init__(name, instrument=instrument, **kwargs)
 
         self.set = self._wrap_set(self.set_raw)
@@ -176,6 +181,27 @@
         else:
             self.get_parser = self._separator_parser(separator)
 
+        have_initial_values = [p._initial_value is not None
+                               for p in parameters]
+        if any(have_initial_values):
+            if not all(have_initial_values):
+                params_with_initial_values = [p.name for p in parameters
+                                              if p._initial_value is not None]
+                params_without_initial_values = [p.name for p in parameters
+                                                 if p._initial_value is None]
+                error_msg = (f'Either none or all of the parameters in a '
+                             f'group should have an initial value. Found '
+                             f'initial values for '
+                             f'{params_with_initial_values} but not for '
+                             f'{params_without_initial_values}.')
+                raise ValueError(error_msg)
+
+            calling_dict = {name: p._initial_value
+                            for name, p in self.parameters.items()}
+
+            self._set_from_dict(calling_dict)
+
+
     def _separator_parser(self, separator: str
                           ) -> Callable[[str], Dict[str, Any]]:
         """A default separator-based string parser"""
@@ -200,6 +226,14 @@
         calling_dict = {name: p.raw_value
                         for name, p in self.parameters.items()}
         calling_dict[set_parameter.name] = value
+
+        self._set_from_dict(calling_dict)
+
+    def _set_from_dict(self, calling_dict: Dict[str, Any]):
+        """
+        Use ``set_cmd`` to parse a dict that maps parameter names to parameter
+        values, and actually perform setting the values.
+        """
         if self.set_cmd is None:
             raise RuntimeError("Calling set but no `set_cmd` defined")
         command_str = self.set_cmd.format(**calling_dict)

{"golden_diff": "diff --git a/qcodes/instrument/group_parameter.py b/qcodes/instrument/group_parameter.py\n--- a/qcodes/instrument/group_parameter.py\n+++ b/qcodes/instrument/group_parameter.py\n@@ -30,8 +30,11 @@\n \n     Args:\n         name: Name of the parameter.\n-        instrument: Instrument that this parameter belongs to; this\n-              instrument is used by the group to call its get and set commands.\n+        instrument: Instrument that this parameter belongs to; this instrument\n+            is used by the group to call its get and set commands.\n+        initial_value: Initial value of the parameter. Note that either none or\n+            all of the parameters in a :class:`.Group` should have an initial\n+            value.\n \n         **kwargs: All kwargs used by the :class:`.Parameter` class, except\n              ``set_cmd`` and ``get_cmd``.\n@@ -40,6 +43,7 @@\n     def __init__(self,\n                  name: str,\n                  instrument: Optional['Instrument'] = None,\n+                 initial_value: Union[float, int, str, None] = None,\n                  **kwargs\n                  ) -> None:\n \n@@ -48,6 +52,7 @@\n                              \"'get_cmd' kwarg\")\n \n         self.group: Union[Group, None] = None\n+        self._initial_value = initial_value\n         super().__init__(name, instrument=instrument, **kwargs)\n \n         self.set = self._wrap_set(self.set_raw)\n@@ -176,6 +181,27 @@\n         else:\n             self.get_parser = self._separator_parser(separator)\n \n+        have_initial_values = [p._initial_value is not None\n+                               for p in parameters]\n+        if any(have_initial_values):\n+            if not all(have_initial_values):\n+                params_with_initial_values = [p.name for p in parameters\n+                                              if p._initial_value is not None]\n+                params_without_initial_values = [p.name for p in parameters\n+                                                 if p._initial_value is None]\n+                error_msg = (f'Either none or all of the parameters in a '\n+                             f'group should have an initial value. Found '\n+                             f'initial values for '\n+                             f'{params_with_initial_values} but not for '\n+                             f'{params_without_initial_values}.')\n+                raise ValueError(error_msg)\n+\n+            calling_dict = {name: p._initial_value\n+                            for name, p in self.parameters.items()}\n+\n+            self._set_from_dict(calling_dict)\n+\n+\n     def _separator_parser(self, separator: str\n                           ) -> Callable[[str], Dict[str, Any]]:\n         \"\"\"A default separator-based string parser\"\"\"\n@@ -200,6 +226,14 @@\n         calling_dict = {name: p.raw_value\n                         for name, p in self.parameters.items()}\n         calling_dict[set_parameter.name] = value\n+\n+        self._set_from_dict(calling_dict)\n+\n+    def _set_from_dict(self, calling_dict: Dict[str, Any]):\n+        \"\"\"\n+        Use ``set_cmd`` to parse a dict that maps parameter names to parameter\n+        values, and actually perform setting the values.\n+        \"\"\"\n         if self.set_cmd is None:\n             raise RuntimeError(\"Calling set but no `set_cmd` defined\")\n         command_str = self.set_cmd.format(**calling_dict)\n", "issue": "GroupParameter initial_value cannot be set\nHere's a MWE:\r\n```py\r\nfrom qcodes.instrument.group_parameter import GroupParameter, Group\r\nfrom qcodes import Instrument\r\n\r\nclass MyInstrument(Instrument):\r\n    def __init__(self, name, *args, **kwargs):\r\n        super().__init__(name, *args, **kwargs)\r\n\r\n        self.add_parameter(name=\"foo\",\r\n                           initial_value=42,\r\n                           parameter_class=GroupParameter\r\n                          )\r\n\r\n        self.group = Group([self.foo])\r\n\r\ninstr = MyInstrument(\"test\")\r\n```\r\n\r\n### Expected behaviour\r\nThe instrument should have the GroupParameter with the given initial value.\r\n\r\n### Actual behaviour\r\nRaises `RuntimeError(\"Trying to set Group value but no  group defined\")`.\r\n\r\n### Proposed fix\r\nThe `GroupParameter` should defer setting the initial value until it has been added to the group. One way of doing it would be to add something like the following to `GroupParameter.__init__`, before the `super().__init__` call:\r\n```py\r\nif \"initial_value\" in kwargs:\r\n    self._initial_value = kwargs[\"initial_value\"]\r\n    kwargs[\"initial_value\"] = None\r\n```\r\nand then adding a `GroupParameter.add_to_group` method where the value is actually set, and calling that instead of just setting `parameter.group = self` in `Group.__init__`. I'm not 100% sure if this is the right way to do it.\r\n\r\n### System\r\n**qcodes branch**: master\r\n\r\n**qcodes commit**: c7eef82d9ab68afb3546fb3c736f2d5b2ff02a14\r\n\n", "before_files": [{"content": "\"\"\"\nThis module implements a :class:`.Group` intended to hold multiple\nparameters that are to be gotten and set by the same command. The parameters\nshould be of type :class:`GroupParameter`\n\"\"\"\n\n\nfrom collections import OrderedDict\nfrom typing import List, Union, Callable, Dict, Any, Optional\n\nfrom qcodes.instrument.parameter import Parameter\nfrom qcodes import Instrument\n\n\nclass GroupParameter(Parameter):\n    \"\"\"\n    Group parameter is a :class:`.Parameter`, whose value can be set or get\n    only with other group parameters. This happens when an instrument\n    has commands which set and get more than one parameter per call.\n\n    The ``set_raw`` method of a group parameter forwards the call to the\n    group, and the group then makes sure that the values of other parameters\n    within the group are left unchanged. The ``get_raw`` method of a group\n    parameter also forwards the call to the group, and the group makes sure\n    that the command output is parsed correctly, and the value of the\n    parameter of interest is returned.\n\n    After initialization, the group parameters need to be added to a group.\n    See :class:`.Group` for more information.\n\n    Args:\n        name: Name of the parameter.\n        instrument: Instrument that this parameter belongs to; this\n              instrument is used by the group to call its get and set commands.\n\n        **kwargs: All kwargs used by the :class:`.Parameter` class, except\n             ``set_cmd`` and ``get_cmd``.\n    \"\"\"\n\n    def __init__(self,\n                 name: str,\n                 instrument: Optional['Instrument'] = None,\n                 **kwargs\n                 ) -> None:\n\n        if \"set_cmd\" in kwargs or \"get_cmd\" in kwargs:\n            raise ValueError(\"A GroupParameter does not use 'set_cmd' or \"\n                             \"'get_cmd' kwarg\")\n\n        self.group: Union[Group, None] = None\n        super().__init__(name, instrument=instrument, **kwargs)\n\n        self.set = self._wrap_set(self.set_raw)\n\n        self.get_raw = lambda result=None: result if result is not None \\\n            else self._get_raw_value()\n\n        self.get = self._wrap_get(self.get_raw)\n\n    def _get_raw_value(self) -> Any:\n        if self.group is None:\n            raise RuntimeError(\"Trying to get Group value but no \"\n                               \"group defined\")\n        self.group.update()\n        return self.raw_value\n\n    def set_raw(self, value: Any) -> None:\n        if self.group is None:\n            raise RuntimeError(\"Trying to set Group value but no \"\n                               \"group defined\")\n        self.group.set(self, value)\n\n\nclass Group:\n    \"\"\"\n    The group combines :class:`.GroupParameter` s that are to be gotten or set\n    via the same command. The command has to be a string, for example,\n    a VISA command.\n\n    The :class:`Group`'s methods are used within :class:`GroupParameter` in\n    order to properly implement setting and getting of a single parameter in\n    the situation where one command sets or gets more than one parameter.\n\n    The command used for setting values of parameters has to be a format\n    string which contains the names of the parameters the group has been\n    initialized with. For example, if a command has syntax ``CMD a_value,\n    b_value``, where ``a_value`` and ``b_value`` are values of two parameters\n    with names ``a`` and ``b``, then the command string has to be ``CMD {a},\n    {b}``, and the group has to be initialized with two ``GroupParameter`` s\n    ``a_param`` and ``b_param``, where ``a_param.name==\"a\"`` and\n    ``b_param.name==\"b\"``.\n\n    **Note** that by default, it is assumed that the command used for getting\n    values returns a comma-separated list of values of parameters, and their\n    order corresponds to the order of :class:`.GroupParameter` s in the list\n    that is passed to the :class:`Group`'s constructor. Through keyword\n    arguments of the :class:`Group`'s constructor, it is possible to change\n    the separator, and even the parser of the output of the get command.\n\n    The get and set commands are called via the instrument that the first\n    parameter belongs to. It is assumed that all the parameters within the\n    group belong to the same instrument.\n\n    Example:\n\n        ::\n\n            class InstrumentWithGroupParameters(VisaInstrument):\n                def __init__(self, name, address, **kwargs):\n                    super().__init__(name, address, **kwargs)\n\n                    ...\n\n                    # Here is how group of group parameters is defined for\n                    # a simple case of an example \"SGP\" command that sets and gets\n                    # values of \"enabled\" and \"gain\" parameters (it is assumed that\n                    # \"SGP?\" returns the parameter values as comma-separated list\n                    # \"enabled_value,gain_value\")\n                    self.add_parameter('enabled',\n                                       label='Enabled',\n                                       val_mapping={True: 1, False: 0},\n                                       parameter_class=GroupParameter)\n                    self.add_parameter('gain',\n                                       label='Some gain value',\n                                       get_parser=float,\n                                       parameter_class=GroupParameter)\n                    self.output_group = Group([self.enabled, self.gain],\n                                              set_cmd='SGP {enabled}, {gain}',\n                                              get_cmd='SGP?')\n\n                    ...\n\n    Args:\n        parameters: a list of :class:`.GroupParameter` instances which have\n            to be gotten  and set via the same command; the order of\n            parameters in the list should correspond to the order of the\n            values returned by the ``get_cmd``.\n        set_cmd: Format string of the command that is used for setting the\n            valueS of the parameters; for example, ``CMD {a}, {b}``.\n        get_cmd: String of the command that is used for getting the values\n            of the parameters; for example, ``CMD?``.\n        separator: A separator that is used when parsing the output of the\n            ``get_cmd`` in order to obtain the values of the parameters; it\n            is ignored in case a custom ``get_parser`` is used.\n        get_parser: A callable with a single string argument that is used to\n            parse the output of the ``get_cmd``; the callable has to return a\n            dictionary where parameter names are keys, and the values are the\n            values (as directly obtained from the output of the get command;\n            note that parsers within the parameters will take care of\n            individual parsing of their values).\n    \"\"\"\n    def __init__(self,\n                 parameters: List[GroupParameter],\n                 set_cmd: str = None,\n                 get_cmd: str = None,\n                 get_parser: Union[Callable[[str],\n                                            Dict[str, Any]], None] = None,\n                 separator: str = ','\n                 ) -> None:\n        self.parameters = OrderedDict((p.name, p) for p in parameters)\n\n        for p in parameters:\n            p.group = self\n\n        if len(set([p.root_instrument for p in parameters])) > 1:\n            raise ValueError(\n                \"All parameters should belong to the same instrument\")\n\n        self.instrument = parameters[0].root_instrument\n\n        self.set_cmd = set_cmd\n        self.get_cmd = get_cmd\n\n        if get_parser:\n            self.get_parser = get_parser\n        else:\n            self.get_parser = self._separator_parser(separator)\n\n    def _separator_parser(self, separator: str\n                          ) -> Callable[[str], Dict[str, Any]]:\n        \"\"\"A default separator-based string parser\"\"\"\n        def parser(ret_str: str) -> Dict[str, Any]:\n            keys = self.parameters.keys()\n            values = ret_str.split(separator)\n            return dict(zip(keys, values))\n\n        return parser\n\n    def set(self, set_parameter: GroupParameter, value: Any):\n        \"\"\"\n        Sets the value of the given parameter within a group to the given\n        value by calling the ``set_cmd``.\n\n        Args:\n            set_parameter: The parameter within the group to set.\n            value: The new value for this parameter.\n        \"\"\"\n        if any((p.get_latest() is None) for p in self.parameters.values()):\n            self.update()\n        calling_dict = {name: p.raw_value\n                        for name, p in self.parameters.items()}\n        calling_dict[set_parameter.name] = value\n        if self.set_cmd is None:\n            raise RuntimeError(\"Calling set but no `set_cmd` defined\")\n        command_str = self.set_cmd.format(**calling_dict)\n        if self.instrument is None:\n            raise RuntimeError(\"Trying to set GroupParameter not attached \"\n                               \"to any instrument.\")\n        self.instrument.write(command_str)\n\n    def update(self):\n        \"\"\"\n        Update the values of all the parameters within the group by calling\n        the ``get_cmd``.\n        \"\"\"\n        ret = self.get_parser(self.instrument.ask(self.get_cmd))\n        for name, p in list(self.parameters.items()):\n            p.get(result=ret[name])\n", "path": "qcodes/instrument/group_parameter.py"}], "after_files": [{"content": "\"\"\"\nThis module implements a :class:`.Group` intended to hold multiple\nparameters that are to be gotten and set by the same command. The parameters\nshould be of type :class:`GroupParameter`\n\"\"\"\n\n\nfrom collections import OrderedDict\nfrom typing import List, Union, Callable, Dict, Any, Optional\n\nfrom qcodes.instrument.parameter import Parameter\nfrom qcodes import Instrument\n\n\nclass GroupParameter(Parameter):\n    \"\"\"\n    Group parameter is a :class:`.Parameter`, whose value can be set or get\n    only with other group parameters. This happens when an instrument\n    has commands which set and get more than one parameter per call.\n\n    The ``set_raw`` method of a group parameter forwards the call to the\n    group, and the group then makes sure that the values of other parameters\n    within the group are left unchanged. The ``get_raw`` method of a group\n    parameter also forwards the call to the group, and the group makes sure\n    that the command output is parsed correctly, and the value of the\n    parameter of interest is returned.\n\n    After initialization, the group parameters need to be added to a group.\n    See :class:`.Group` for more information.\n\n    Args:\n        name: Name of the parameter.\n        instrument: Instrument that this parameter belongs to; this instrument\n            is used by the group to call its get and set commands.\n        initial_value: Initial value of the parameter. Note that either none or\n            all of the parameters in a :class:`.Group` should have an initial\n            value.\n\n        **kwargs: All kwargs used by the :class:`.Parameter` class, except\n             ``set_cmd`` and ``get_cmd``.\n    \"\"\"\n\n    def __init__(self,\n                 name: str,\n                 instrument: Optional['Instrument'] = None,\n                 initial_value: Union[float, int, str, None] = None,\n                 **kwargs\n                 ) -> None:\n\n        if \"set_cmd\" in kwargs or \"get_cmd\" in kwargs:\n            raise ValueError(\"A GroupParameter does not use 'set_cmd' or \"\n                             \"'get_cmd' kwarg\")\n\n        self.group: Union[Group, None] = None\n        self._initial_value = initial_value\n        super().__init__(name, instrument=instrument, **kwargs)\n\n        self.set = self._wrap_set(self.set_raw)\n\n        self.get_raw = lambda result=None: result if result is not None \\\n            else self._get_raw_value()\n\n        self.get = self._wrap_get(self.get_raw)\n\n    def _get_raw_value(self) -> Any:\n        if self.group is None:\n            raise RuntimeError(\"Trying to get Group value but no \"\n                               \"group defined\")\n        self.group.update()\n        return self.raw_value\n\n    def set_raw(self, value: Any) -> None:\n        if self.group is None:\n            raise RuntimeError(\"Trying to set Group value but no \"\n                               \"group defined\")\n        self.group.set(self, value)\n\n\nclass Group:\n    \"\"\"\n    The group combines :class:`.GroupParameter` s that are to be gotten or set\n    via the same command. The command has to be a string, for example,\n    a VISA command.\n\n    The :class:`Group`'s methods are used within :class:`GroupParameter` in\n    order to properly implement setting and getting of a single parameter in\n    the situation where one command sets or gets more than one parameter.\n\n    The command used for setting values of parameters has to be a format\n    string which contains the names of the parameters the group has been\n    initialized with. For example, if a command has syntax ``CMD a_value,\n    b_value``, where ``a_value`` and ``b_value`` are values of two parameters\n    with names ``a`` and ``b``, then the command string has to be ``CMD {a},\n    {b}``, and the group has to be initialized with two ``GroupParameter`` s\n    ``a_param`` and ``b_param``, where ``a_param.name==\"a\"`` and\n    ``b_param.name==\"b\"``.\n\n    **Note** that by default, it is assumed that the command used for getting\n    values returns a comma-separated list of values of parameters, and their\n    order corresponds to the order of :class:`.GroupParameter` s in the list\n    that is passed to the :class:`Group`'s constructor. Through keyword\n    arguments of the :class:`Group`'s constructor, it is possible to change\n    the separator, and even the parser of the output of the get command.\n\n    The get and set commands are called via the instrument that the first\n    parameter belongs to. It is assumed that all the parameters within the\n    group belong to the same instrument.\n\n    Example:\n\n        ::\n\n            class InstrumentWithGroupParameters(VisaInstrument):\n                def __init__(self, name, address, **kwargs):\n                    super().__init__(name, address, **kwargs)\n\n                    ...\n\n                    # Here is how group of group parameters is defined for\n                    # a simple case of an example \"SGP\" command that sets and gets\n                    # values of \"enabled\" and \"gain\" parameters (it is assumed that\n                    # \"SGP?\" returns the parameter values as comma-separated list\n                    # \"enabled_value,gain_value\")\n                    self.add_parameter('enabled',\n                                       label='Enabled',\n                                       val_mapping={True: 1, False: 0},\n                                       parameter_class=GroupParameter)\n                    self.add_parameter('gain',\n                                       label='Some gain value',\n                                       get_parser=float,\n                                       parameter_class=GroupParameter)\n                    self.output_group = Group([self.enabled, self.gain],\n                                              set_cmd='SGP {enabled}, {gain}',\n                                              get_cmd='SGP?')\n\n                    ...\n\n    Args:\n        parameters: a list of :class:`.GroupParameter` instances which have\n            to be gotten  and set via the same command; the order of\n            parameters in the list should correspond to the order of the\n            values returned by the ``get_cmd``.\n        set_cmd: Format string of the command that is used for setting the\n            valueS of the parameters; for example, ``CMD {a}, {b}``.\n        get_cmd: String of the command that is used for getting the values\n            of the parameters; for example, ``CMD?``.\n        separator: A separator that is used when parsing the output of the\n            ``get_cmd`` in order to obtain the values of the parameters; it\n            is ignored in case a custom ``get_parser`` is used.\n        get_parser: A callable with a single string argument that is used to\n            parse the output of the ``get_cmd``; the callable has to return a\n            dictionary where parameter names are keys, and the values are the\n            values (as directly obtained from the output of the get command;\n            note that parsers within the parameters will take care of\n            individual parsing of their values).\n    \"\"\"\n    def __init__(self,\n                 parameters: List[GroupParameter],\n                 set_cmd: str = None,\n                 get_cmd: str = None,\n                 get_parser: Union[Callable[[str],\n                                            Dict[str, Any]], None] = None,\n                 separator: str = ','\n                 ) -> None:\n        self.parameters = OrderedDict((p.name, p) for p in parameters)\n\n        for p in parameters:\n            p.group = self\n\n        if len(set([p.root_instrument for p in parameters])) > 1:\n            raise ValueError(\n                \"All parameters should belong to the same instrument\")\n\n        self.instrument = parameters[0].root_instrument\n\n        self.set_cmd = set_cmd\n        self.get_cmd = get_cmd\n\n        if get_parser:\n            self.get_parser = get_parser\n        else:\n            self.get_parser = self._separator_parser(separator)\n\n        have_initial_values = [p._initial_value is not None\n                               for p in parameters]\n        if any(have_initial_values):\n            if not all(have_initial_values):\n                params_with_initial_values = [p.name for p in parameters\n                                              if p._initial_value is not None]\n                params_without_initial_values = [p.name for p in parameters\n                                                 if p._initial_value is None]\n                error_msg = (f'Either none or all of the parameters in a '\n                             f'group should have an initial value. Found '\n                             f'initial values for '\n                             f'{params_with_initial_values} but not for '\n                             f'{params_without_initial_values}.')\n                raise ValueError(error_msg)\n\n            calling_dict = {name: p._initial_value\n                            for name, p in self.parameters.items()}\n\n            self._set_from_dict(calling_dict)\n\n\n    def _separator_parser(self, separator: str\n                          ) -> Callable[[str], Dict[str, Any]]:\n        \"\"\"A default separator-based string parser\"\"\"\n        def parser(ret_str: str) -> Dict[str, Any]:\n            keys = self.parameters.keys()\n            values = ret_str.split(separator)\n            return dict(zip(keys, values))\n\n        return parser\n\n    def set(self, set_parameter: GroupParameter, value: Any):\n        \"\"\"\n        Sets the value of the given parameter within a group to the given\n        value by calling the ``set_cmd``.\n\n        Args:\n            set_parameter: The parameter within the group to set.\n            value: The new value for this parameter.\n        \"\"\"\n        if any((p.get_latest() is None) for p in self.parameters.values()):\n            self.update()\n        calling_dict = {name: p.raw_value\n                        for name, p in self.parameters.items()}\n        calling_dict[set_parameter.name] = value\n\n        self._set_from_dict(calling_dict)\n\n    def _set_from_dict(self, calling_dict: Dict[str, Any]):\n        \"\"\"\n        Use ``set_cmd`` to parse a dict that maps parameter names to parameter\n        values, and actually perform setting the values.\n        \"\"\"\n        if self.set_cmd is None:\n            raise RuntimeError(\"Calling set but no `set_cmd` defined\")\n        command_str = self.set_cmd.format(**calling_dict)\n        if self.instrument is None:\n            raise RuntimeError(\"Trying to set GroupParameter not attached \"\n                               \"to any instrument.\")\n        self.instrument.write(command_str)\n\n    def update(self):\n        \"\"\"\n        Update the values of all the parameters within the group by calling\n        the ``get_cmd``.\n        \"\"\"\n        ret = self.get_parser(self.instrument.ask(self.get_cmd))\n        for name, p in list(self.parameters.items()):\n            p.get(result=ret[name])\n", "path": "qcodes/instrument/group_parameter.py"}]}