Repository: microsoft/Qcodes

Issue:
Add name parameter to Measurement class
The `Measurement` class has the attribute `name`, which is currently hardcoded to an empty string ([here](https://github.com/QCoDeS/Qcodes/blob/master/qcodes/dataset/measurements.py#L686)). Because of this, doing `with meas.run() as datasaver: ...` will always give the dataset the name `"results"` ([here](https://github.com/QCoDeS/Qcodes/blob/master/qcodes/dataset/measurements.py#L582)). Would it be possible to add a `name` argument to the Measurement constructor? So that the `__repr__` of a dataset could be slightly more informative.

Or does this mess up something with the database? As in https://github.com/QCoDeS/Qcodes/issues/898


Discussion:
`name` is just an attribute, so it is possible to change the `name` of a `Measurement` object after its instantiation but before the `with meas.run() as datasaver: ...` context. This will not break the database in any way.

But i agree that passing the name via `__init__` is cleaner. Moreover, `name` should ideally be a `property`. Would you be willing to make a PR with this change?
If I add `name` to the constructor, I guess it should be the first parameter to be consistent with everything else. But this might break some scripts which assume that the signature is `Measurement(experiment, station)`. In the examples the parameters are always named (which is good) but I see that in my own scripts I've done this. For my scripts it's not a big deal, but do you think the constructor should also accept an Experiment object as the name parameter, with an appropriate deprecation warning? Or is this such an easy fix that it's okay to break old scripts?
> I guess it should be the first parameter to be consistent with everything else

yet, but backwards compatibility it more important. So, let's have `name` as a kwarg.

> but do you think the constructor should also accept an Experiment object as the name parameter, with an appropriate deprecation warning

sure, that'd be great. But i do not think there's much value in the effort investment that it prescribes.

-------

another question. currently, it is possible to change the `name` after `Measurement` object is instantiated. Shall we keep this behavior? I think it's fair to keep because it allows to run an existing measurement with all the registered parameters under a different name which might be useful. opinions @QCoDeS/core ?

Resolving patch:
diff --git a/qcodes/dataset/measurements.py b/qcodes/dataset/measurements.py
--- a/qcodes/dataset/measurements.py
+++ b/qcodes/dataset/measurements.py
@@ -68,7 +68,7 @@ def is_number(thing: Any) -> bool:
 
 class DataSaver:
     """
-    The class used by the class:`Runner` context manager to handle the
+    The class used by the :class:`Runner` context manager to handle the
     datasaving to the database.
     """
 
@@ -672,18 +672,23 @@ class Measurement:
             is the latest one created.
         station: The QCoDeS station to snapshot. If not given, the
             default one is used.
+        name: Name of the experiment. This will be passed down to the dataset
+            produced by the measurement. If not given, a default value of
+            'results' is used for the dataset.
     """
 
     def __init__(self, exp: Optional[Experiment] = None,
-                 station: Optional[qc.Station] = None) -> None:
+                 station: Optional[qc.Station] = None,
+                 name: str = '') -> None:
         self.exitactions: List[Tuple[Callable, Sequence]] = []
         self.enteractions: List[Tuple[Callable, Sequence]] = []
         self.subscribers: List[Tuple[Callable, Union[MutableSequence,
                                                      MutableMapping]]] = []
+
         self.experiment = exp
         self.station = station
+        self.name = name
         self._write_period: Optional[float] = None
-        self.name = ''
         self._interdeps = InterDependencies_()
         self._parent_datasets: List[Dict] = []
 


Test patch:
diff --git a/qcodes/tests/dataset/test_measurement_context_manager.py b/qcodes/tests/dataset/test_measurement_context_manager.py
--- a/qcodes/tests/dataset/test_measurement_context_manager.py
+++ b/qcodes/tests/dataset/test_measurement_context_manager.py
@@ -398,7 +398,26 @@ def test_mixing_array_and_numeric(DAC):
                              (DAC.ch2, np.array([DAC.ch2(), DAC.ch1()])))
 
 
-def test_measurement_name(experiment, DAC, DMM):
+def test_measurement_name_default(experiment, DAC, DMM):
+    fmt = experiment.format_string
+    exp_id = experiment.exp_id
+
+    default_name = 'results'
+
+    meas = Measurement()
+    assert meas.name == ''
+
+    meas.register_parameter(DAC.ch1)
+    meas.register_parameter(DMM.v1, setpoints=[DAC.ch1])
+
+    with meas.run() as datasaver:
+        run_id = datasaver.run_id
+        expected_name = fmt.format(default_name, exp_id, run_id)
+        assert datasaver.dataset.table_name == expected_name
+        assert datasaver.dataset.name == default_name
+
+
+def test_measurement_name_changed_via_attribute(experiment, DAC, DMM):
     fmt = experiment.format_string
     exp_id = experiment.exp_id
 
@@ -414,6 +433,25 @@ def test_measurement_name(experiment, DAC, DMM):
         run_id = datasaver.run_id
         expected_name = fmt.format(name, exp_id, run_id)
         assert datasaver.dataset.table_name == expected_name
+        assert datasaver.dataset.name == name
+
+
+def test_measurement_name_set_as_argument(experiment, DAC, DMM):
+    fmt = experiment.format_string
+    exp_id = experiment.exp_id
+
+    name = 'yolo'
+
+    meas = Measurement(name=name, exp=experiment)
+
+    meas.register_parameter(DAC.ch1)
+    meas.register_parameter(DMM.v1, setpoints=[DAC.ch1])
+
+    with meas.run() as datasaver:
+        run_id = datasaver.run_id
+        expected_name = fmt.format(name, exp_id, run_id)
+        assert datasaver.dataset.table_name == expected_name
+        assert datasaver.dataset.name == name
 
 
 @settings(deadline=None)