Repository: microsoft/Qcodes

Issue:
example /Load-and-plot-old-data.ipynb is broken
The example fails with the error: `ValueError: ('unrecognized DataSet mode', None)`
This is due to recent changes in data_set.py

Maybe it would be good to run the example ipython notebooks as part of the testing procedure. For example add the following to test.py

``` python
    from runipy.notebook_runner import NotebookRunner
    from nbformat.current import read

    notebook = read(open("docs/examples/Load-and-plot-old-data.ipynb"), 'json')
    r = NotebookRunner(notebook)
    try:
        r.run_notebook()
    except:
        print('error in example notebook....')
```



Discussion:
Oh, that's cool, I didn't know about `NotebookRunner`! We'd have to be a bit careful to make the other notebook run straight through, since it has background tasks and you can't run one `Loop` until the previous has finished...

But yeah, I committed that notebook accidentally, wondered if anyone would notice. You caught me :flushed: 

@alexcjohnson I think `mode=qcodes.DataMode.LOCAL` might be a good default setting for a `DataSet`.

I suggest we make `qcodes.DataMode.LOCAL` the default (which will solve the problem) and close the issue. The alternative is to fix the example notebook.

I just ran into this, and agree with @eendebakpt that we should just make the LOCAL the default one, any reasons to not do this @alexcjohnson ?


Resolving patch:
diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -1,7 +1,7 @@
 from enum import Enum
 from datetime import datetime
 
-from .manager import get_data_manager
+from .manager import get_data_manager, NoData
 from .format import GNUPlotFormat
 from .io import DiskIO
 from qcodes.utils.helpers import DelegateAttributes
@@ -86,6 +86,10 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
         return _get_live_data(data_manager)
 
+    elif location is False:
+        raise ValueError('location=False means a temporary DataSet, '
+                         'which is incompatible with load_data')
+
     elif (data_manager and
             location == data_manager.ask('get_data', 'location')):
         return _get_live_data(data_manager)
@@ -97,7 +101,7 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
 def _get_live_data(data_manager):
     live_data = data_manager.ask('get_data')
-    if live_data is None:
+    if live_data is None or isinstance(live_data, NoData):
         raise RuntimeError('DataManager has no live data')
 
     live_data.mode = DataMode.PULL_FROM_SERVER
@@ -181,7 +185,7 @@ class DataSet(DelegateAttributes):
     default_formatter = GNUPlotFormat()
     location_provider = TimestampLocation()
 
-    def __init__(self, location=None, mode=None, arrays=None,
+    def __init__(self, location=None, mode=DataMode.LOCAL, arrays=None,
                  data_manager=None, formatter=None, io=None):
         if location is False or isinstance(location, str):
             self.location = location
@@ -199,7 +203,7 @@ def __init__(self, location=None, mode=None, arrays=None,
             for array in arrays:
                 self.add_array(array)
 
-        if data_manager is None:
+        if data_manager is None and mode in SERVER_MODES:
             data_manager = get_data_manager()
 
         if mode == DataMode.LOCAL:
diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -221,10 +221,13 @@ def delattr(self, attr, prune=True):
                     delattr(self, attr[0])
 
     def __del__(self):
-        wr = weakref.ref(self)
-        if wr in getattr(self, '_instances', {}):
-            self._instances.remove(wr)
-        self.close()
+        try:
+            wr = weakref.ref(self)
+            if wr in getattr(self, '_instances', {}):
+                self._instances.remove(wr)
+            self.close()
+        except:
+            pass
 
     def close(self):
         '''


Test patch:
diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py
--- a/qcodes/tests/instrument_mocks.py
+++ b/qcodes/tests/instrument_mocks.py
@@ -95,6 +95,8 @@ def add5(self, b):
 
 class MockGates(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('gates', model=model, delay=0.001, **kwargs)
+
         for i in range(3):
             cmdbase = 'c{}'.format(i)
             self.add_parameter('chan{}'.format(i), get_cmd=cmdbase + '?',
@@ -123,8 +125,6 @@ def __init__(self, model=None, **kwargs):
 
         self.add_function('reset', call_cmd='rst')
 
-        super().__init__('gates', model=model, delay=0.001, **kwargs)
-
     def slow_neg_set(self, val):
         if val < 0:
             time.sleep(0.05)
@@ -133,18 +133,18 @@ def slow_neg_set(self, val):
 
 class MockSource(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('source', model=model, delay=0.001, **kwargs)
+
         self.add_parameter('amplitude', get_cmd='ampl?',
                            set_cmd='ampl:{:.4f}', get_parser=float,
                            vals=Numbers(0, 1),
                            sweep_step=0.2, sweep_delay=0.005)
 
-        super().__init__('source', model=model, delay=0.001, **kwargs)
-
 
 class MockMeter(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('meter', model=model, delay=0.001, **kwargs)
+
         self.add_parameter('amplitude', get_cmd='ampl?', get_parser=float)
         self.add_function('echo', call_cmd='echo {:.2f}?',
                           args=[Numbers(0, 1000)], return_parser=float)
-
-        super().__init__('meter', model=model, delay=0.001, **kwargs)
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -2,6 +2,10 @@
 import numpy as np
 
 from qcodes.data.data_array import DataArray
+from qcodes.data.manager import get_data_manager
+from qcodes.data.data_set import load_data
+from qcodes.utils.helpers import killprocesses
+from qcodes import active_children
 
 
 class TestDataArray(TestCase):
@@ -198,3 +202,29 @@ def test_data_set_property(self):
         self.assertIsNone(data.data_set)
         data.data_set = mock_data_set2
         self.assertEqual(data.data_set, mock_data_set2)
+
+
+class TestLoadData(TestCase):
+    def setUp(self):
+        killprocesses()
+
+    def test_no_live_data(self):
+        # live data with no DataManager at all
+        with self.assertRaises(RuntimeError):
+            load_data()
+        self.assertEqual(len(active_children()), 0)
+
+        # now make a DataManager and try again
+        get_data_manager()
+        self.assertEqual(len(active_children()), 1)
+        # same result but different code path
+        with self.assertRaises(RuntimeError):
+            load_data()
+
+    def test_no_saved_data(self):
+        with self.assertRaises(IOError):
+            load_data('_no/such/file_')
+
+    def test_load_false(self):
+        with self.assertRaises(ValueError):
+            load_data(False)