qcodes 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qcodes/__init__.py +65 -0
- qcodes/actions.py +207 -0
- qcodes/config/__init__.py +2 -0
- qcodes/config/config.py +396 -0
- qcodes/config/qcodesrc.json +11 -0
- qcodes/config/qcodesrc_schema.json +55 -0
- qcodes/data/__init__.py +0 -0
- qcodes/data/data_array.py +520 -0
- qcodes/data/data_set.py +803 -0
- qcodes/data/format.py +309 -0
- qcodes/data/gnuplot_format.py +366 -0
- qcodes/data/hdf5_format.py +385 -0
- qcodes/data/io.py +266 -0
- qcodes/data/location.py +166 -0
- qcodes/data/manager.py +163 -0
- qcodes/instrument/__init__.py +0 -0
- qcodes/instrument/base.py +630 -0
- qcodes/instrument/function.py +134 -0
- qcodes/instrument/ip.py +236 -0
- qcodes/instrument/metaclass.py +45 -0
- qcodes/instrument/mock.py +278 -0
- qcodes/instrument/parameter.py +1001 -0
- qcodes/instrument/remote.py +529 -0
- qcodes/instrument/server.py +189 -0
- qcodes/instrument/sweep_values.py +286 -0
- qcodes/instrument/visa.py +198 -0
- qcodes/instrument_drivers/AlazarTech/ATS.py +1001 -0
- qcodes/instrument_drivers/AlazarTech/ATS9870.py +266 -0
- qcodes/instrument_drivers/AlazarTech/ATS_acquisition_controllers.py +143 -0
- qcodes/instrument_drivers/AlazarTech/__init__.py +0 -0
- qcodes/instrument_drivers/QuTech/IVVI.py +390 -0
- qcodes/instrument_drivers/QuTech/__init__.py +0 -0
- qcodes/instrument_drivers/__init__.py +0 -0
- qcodes/instrument_drivers/agilent/Agilent_34400A.py +155 -0
- qcodes/instrument_drivers/agilent/E8527D.py +79 -0
- qcodes/instrument_drivers/agilent/HP33210A.py +104 -0
- qcodes/instrument_drivers/agilent/__init__.py +0 -0
- qcodes/instrument_drivers/agilent/test_suite.py +96 -0
- qcodes/instrument_drivers/ithaco/Ithaco_1211.py +110 -0
- qcodes/instrument_drivers/ithaco/__init__.py +0 -0
- qcodes/instrument_drivers/oxford/__init__.py +0 -0
- qcodes/instrument_drivers/oxford/mercuryiPS.py +358 -0
- qcodes/instrument_drivers/oxford/triton.py +227 -0
- qcodes/instrument_drivers/rigol/DG4000.py +591 -0
- qcodes/instrument_drivers/rigol/__init__.py +0 -0
- qcodes/instrument_drivers/rohde_schwarz/SGS100A.py +99 -0
- qcodes/instrument_drivers/rohde_schwarz/ZNB20.py +154 -0
- qcodes/instrument_drivers/rohde_schwarz/__init__.py +0 -0
- qcodes/instrument_drivers/signal_hound/USB_SA124B.py +567 -0
- qcodes/instrument_drivers/signal_hound/__init__.py +0 -0
- qcodes/instrument_drivers/stanford_research/SR560.py +116 -0
- qcodes/instrument_drivers/stanford_research/SR830.py +314 -0
- qcodes/instrument_drivers/stanford_research/SR865.py +305 -0
- qcodes/instrument_drivers/stanford_research/__init__.py +0 -0
- qcodes/instrument_drivers/tektronix/AWG5014.py +1228 -0
- qcodes/instrument_drivers/tektronix/AWG520.py +659 -0
- qcodes/instrument_drivers/tektronix/Keithley_2000.py +195 -0
- qcodes/instrument_drivers/tektronix/Keithley_2600.py +83 -0
- qcodes/instrument_drivers/tektronix/Keithley_2700.py +395 -0
- qcodes/instrument_drivers/tektronix/__init__.py +0 -0
- qcodes/instrument_drivers/test.py +94 -0
- qcodes/instrument_drivers/weinschel/Weinschel_8320.py +21 -0
- qcodes/instrument_drivers/weinschel/__init__.py +0 -0
- qcodes/instrument_drivers/weinschel/test_suite.py +27 -0
- qcodes/loops.py +1009 -0
- qcodes/measure.py +155 -0
- qcodes/plots/__init__.py +0 -0
- qcodes/plots/base.py +280 -0
- qcodes/plots/colors.py +135 -0
- qcodes/plots/pyqtgraph.py +384 -0
- qcodes/plots/qcmatplotlib.py +206 -0
- qcodes/process/__init__.py +0 -0
- qcodes/process/helpers.py +60 -0
- qcodes/process/qcodes_process.py +72 -0
- qcodes/process/server.py +395 -0
- qcodes/process/stream_queue.py +152 -0
- qcodes/station.py +178 -0
- qcodes/test.py +119 -0
- qcodes/tests/__init__.py +0 -0
- qcodes/tests/common.py +7 -0
- qcodes/tests/data_mocks.py +173 -0
- qcodes/tests/instrument_mocks.py +327 -0
- qcodes/tests/py35_syntax.py +13 -0
- qcodes/tests/test_combined_par.py +156 -0
- qcodes/tests/test_command.py +120 -0
- qcodes/tests/test_config.py +222 -0
- qcodes/tests/test_data.py +668 -0
- qcodes/tests/test_deferred_operations.py +105 -0
- qcodes/tests/test_driver_testcase.py +58 -0
- qcodes/tests/test_format.py +414 -0
- qcodes/tests/test_hdf5formatter.py +333 -0
- qcodes/tests/test_helpers.py +630 -0
- qcodes/tests/test_instrument.py +981 -0
- qcodes/tests/test_instrument_server.py +156 -0
- qcodes/tests/test_json.py +48 -0
- qcodes/tests/test_location_provider.py +109 -0
- qcodes/tests/test_loop.py +825 -0
- qcodes/tests/test_measure.py +49 -0
- qcodes/tests/test_metadata.py +49 -0
- qcodes/tests/test_multiprocessing.py +471 -0
- qcodes/tests/test_nested_attrs.py +100 -0
- qcodes/tests/test_parameter.py +151 -0
- qcodes/tests/test_plots.py +44 -0
- qcodes/tests/test_sweep_values.py +159 -0
- qcodes/tests/test_validators.py +482 -0
- qcodes/tests/test_visa.py +184 -0
- qcodes/utils/__init__.py +0 -0
- qcodes/utils/command.py +176 -0
- qcodes/utils/deferred_operations.py +276 -0
- qcodes/utils/helpers.py +417 -0
- qcodes/utils/metadata.py +42 -0
- qcodes/utils/nested_attrs.py +177 -0
- qcodes/utils/reload_code.py +98 -0
- qcodes/utils/threading.py +72 -0
- qcodes/utils/timing.py +89 -0
- qcodes/utils/validators.py +393 -0
- qcodes/version.py +1 -0
- qcodes/widgets/__init__.py +0 -0
- qcodes/widgets/display.py +47 -0
- qcodes/widgets/widgets.css +77 -0
- qcodes/widgets/widgets.js +237 -0
- qcodes/widgets/widgets.py +215 -0
- qcodes-0.1.0.dist-info/DESCRIPTION.rst +165 -0
- qcodes-0.1.0.dist-info/METADATA +194 -0
- qcodes-0.1.0.dist-info/RECORD +128 -0
- qcodes-0.1.0.dist-info/WHEEL +5 -0
- qcodes-0.1.0.dist-info/metadata.json +1 -0
- qcodes-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
from unittest import TestCase
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
import numpy as np
|
|
4
|
+
import os
|
|
5
|
+
import pickle
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from qcodes.data.data_array import DataArray
|
|
9
|
+
from qcodes.data.manager import get_data_manager, NoData
|
|
10
|
+
from qcodes.data.io import DiskIO
|
|
11
|
+
from qcodes.data.data_set import load_data, new_data, DataMode, DataSet
|
|
12
|
+
from qcodes.process.helpers import kill_processes
|
|
13
|
+
from qcodes.utils.helpers import LogCapture
|
|
14
|
+
from qcodes import active_children
|
|
15
|
+
|
|
16
|
+
from .data_mocks import (MockDataManager, MockFormatter, MatchIO,
|
|
17
|
+
MockLive, MockArray, DataSet2D, DataSet1D,
|
|
18
|
+
DataSetCombined, RecordingMockFormatter)
|
|
19
|
+
from .common import strip_qc
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestDataArray(TestCase):
|
|
23
|
+
|
|
24
|
+
def test_attributes(self):
|
|
25
|
+
pname = 'Betty Sue'
|
|
26
|
+
plabel = 'The best apple pie this side of Wenatchee'
|
|
27
|
+
pfullname = 'bert'
|
|
28
|
+
|
|
29
|
+
class MockParam:
|
|
30
|
+
name = pname
|
|
31
|
+
label = plabel
|
|
32
|
+
|
|
33
|
+
def __init__(self, full_name=None):
|
|
34
|
+
self.full_name = full_name
|
|
35
|
+
|
|
36
|
+
name = 'Oscar'
|
|
37
|
+
label = 'The grouch. GRR!'
|
|
38
|
+
fullname = 'ernie'
|
|
39
|
+
array_id = 24601
|
|
40
|
+
set_arrays = ('awesomeness', 'chocolate content')
|
|
41
|
+
shape = 'Ginornous'
|
|
42
|
+
action_indices = (1, 2, 3, 4, 5)
|
|
43
|
+
|
|
44
|
+
p_data = DataArray(parameter=MockParam(pfullname), name=name,
|
|
45
|
+
label=label, full_name=fullname)
|
|
46
|
+
p_data2 = DataArray(parameter=MockParam(pfullname))
|
|
47
|
+
|
|
48
|
+
# explicitly given name and label override parameter vals
|
|
49
|
+
self.assertEqual(p_data.name, name)
|
|
50
|
+
self.assertEqual(p_data.label, label)
|
|
51
|
+
self.assertEqual(p_data.full_name, fullname)
|
|
52
|
+
self.assertEqual(p_data2.name, pname)
|
|
53
|
+
self.assertEqual(p_data2.label, plabel)
|
|
54
|
+
self.assertEqual(p_data2.full_name, pfullname)
|
|
55
|
+
# test default values
|
|
56
|
+
self.assertIsNone(p_data.array_id)
|
|
57
|
+
self.assertEqual(p_data.shape, ())
|
|
58
|
+
self.assertEqual(p_data.action_indices, ())
|
|
59
|
+
self.assertEqual(p_data.set_arrays, ())
|
|
60
|
+
self.assertIsNone(p_data.ndarray)
|
|
61
|
+
|
|
62
|
+
np_data = DataArray(name=name, label=label, array_id=array_id,
|
|
63
|
+
set_arrays=set_arrays, shape=shape,
|
|
64
|
+
action_indices=action_indices)
|
|
65
|
+
self.assertEqual(np_data.name, name)
|
|
66
|
+
self.assertEqual(np_data.label, label)
|
|
67
|
+
# no full name or parameter - use name
|
|
68
|
+
self.assertEqual(np_data.full_name, name)
|
|
69
|
+
# test simple assignments
|
|
70
|
+
self.assertEqual(np_data.array_id, array_id)
|
|
71
|
+
self.assertEqual(np_data.set_arrays, set_arrays)
|
|
72
|
+
self.assertEqual(np_data.shape, shape)
|
|
73
|
+
self.assertEqual(np_data.action_indices, action_indices)
|
|
74
|
+
|
|
75
|
+
name_data = DataArray(name=name)
|
|
76
|
+
self.assertEqual(name_data.label, name)
|
|
77
|
+
|
|
78
|
+
blank_data = DataArray()
|
|
79
|
+
self.assertIsNone(blank_data.name)
|
|
80
|
+
|
|
81
|
+
def test_preset_data(self):
|
|
82
|
+
onetwothree = [
|
|
83
|
+
# lists and tuples work
|
|
84
|
+
[1.0, 2.0, 3.0],
|
|
85
|
+
(1.0, 2.0, 3.0),
|
|
86
|
+
|
|
87
|
+
# iterators get automatically cast to floats
|
|
88
|
+
(i + 1 for i in range(3)),
|
|
89
|
+
map(float, range(1, 4)),
|
|
90
|
+
|
|
91
|
+
# and of course numpy arrays themselves work
|
|
92
|
+
np.array([1.0, 2.0, 3.0]),
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
expected123 = [1.0, 2.0, 3.0]
|
|
96
|
+
|
|
97
|
+
for item in onetwothree:
|
|
98
|
+
data = DataArray(preset_data=item)
|
|
99
|
+
self.assertEqual(data.ndarray.tolist(), expected123)
|
|
100
|
+
self.assertEqual(data.shape, (3, ))
|
|
101
|
+
|
|
102
|
+
# you can re-initialize a DataArray with the same shape data,
|
|
103
|
+
# but not with a different shape
|
|
104
|
+
list456 = [4, 5, 6]
|
|
105
|
+
data.init_data(data=list456)
|
|
106
|
+
self.assertEqual(data.ndarray.tolist(), list456)
|
|
107
|
+
with self.assertRaises(ValueError):
|
|
108
|
+
data.init_data([1, 2])
|
|
109
|
+
self.assertEqual(data.ndarray.tolist(), list456)
|
|
110
|
+
self.assertEqual(data.shape, (3, ))
|
|
111
|
+
|
|
112
|
+
# you can call init_data again with no data, and nothing changes
|
|
113
|
+
data.init_data()
|
|
114
|
+
self.assertEqual(data.ndarray.tolist(), list456)
|
|
115
|
+
self.assertEqual(data.shape, (3, ))
|
|
116
|
+
|
|
117
|
+
# multidimensional works too
|
|
118
|
+
list2d = [[1, 2], [3, 4]]
|
|
119
|
+
data2 = DataArray(preset_data=list2d)
|
|
120
|
+
self.assertEqual(data2.ndarray.tolist(), list2d)
|
|
121
|
+
self.assertEqual(data2.shape, (2, 2))
|
|
122
|
+
|
|
123
|
+
def test_init_data_error(self):
|
|
124
|
+
data = DataArray(preset_data=[1, 2])
|
|
125
|
+
data.shape = (3, )
|
|
126
|
+
|
|
127
|
+
# not sure when this would happen... but if you call init_data
|
|
128
|
+
# and it notices an inconsistency between shape and the actual
|
|
129
|
+
# data that's already there, it raises an error
|
|
130
|
+
with self.assertRaises(ValueError):
|
|
131
|
+
data.init_data()
|
|
132
|
+
|
|
133
|
+
def test_clear(self):
|
|
134
|
+
nan = float('nan')
|
|
135
|
+
data = DataArray(preset_data=[1, 2])
|
|
136
|
+
data.clear()
|
|
137
|
+
# sometimes it's annoying that nan != nan
|
|
138
|
+
self.assertEqual(repr(data.ndarray.tolist()), repr([nan, nan]))
|
|
139
|
+
|
|
140
|
+
def test_edit_and_mark(self):
|
|
141
|
+
data = DataArray(preset_data=[[1, 2], [3, 4]])
|
|
142
|
+
self.assertEqual(data[0].tolist(), [1, 2])
|
|
143
|
+
self.assertEqual(data[0, 1], 2)
|
|
144
|
+
|
|
145
|
+
data.modified_range = None
|
|
146
|
+
self.assertIsNone(data.last_saved_index)
|
|
147
|
+
|
|
148
|
+
self.assertEqual(len(data), 2)
|
|
149
|
+
data[0] = np.array([5, 6])
|
|
150
|
+
data[1, 0] = 7
|
|
151
|
+
self.assertEqual(data.ndarray.tolist(), [[5, 6], [7, 4]])
|
|
152
|
+
|
|
153
|
+
self.assertEqual(data.modified_range, (0, 2))
|
|
154
|
+
|
|
155
|
+
# as if we saved the first two points... the third should still
|
|
156
|
+
# show as modified
|
|
157
|
+
data.mark_saved(1)
|
|
158
|
+
self.assertEqual(data.last_saved_index, 1)
|
|
159
|
+
self.assertEqual(data.modified_range, (2, 2))
|
|
160
|
+
|
|
161
|
+
# now we save the third point... no modifications left.
|
|
162
|
+
data.mark_saved(2)
|
|
163
|
+
self.assertEqual(data.last_saved_index, 2)
|
|
164
|
+
self.assertEqual(data.modified_range, None)
|
|
165
|
+
|
|
166
|
+
data.clear_save()
|
|
167
|
+
self.assertEqual(data.last_saved_index, None)
|
|
168
|
+
self.assertEqual(data.modified_range, (0, 2))
|
|
169
|
+
|
|
170
|
+
def test_edit_and_mark_slice(self):
|
|
171
|
+
data = DataArray(preset_data=[[1] * 5] * 6)
|
|
172
|
+
|
|
173
|
+
self.assertEqual(data.shape, (6, 5))
|
|
174
|
+
data.modified_range = None
|
|
175
|
+
|
|
176
|
+
data[:4:2, 2:] = 2
|
|
177
|
+
self.assertEqual(data.tolist(), [
|
|
178
|
+
[1, 1, 2, 2, 2],
|
|
179
|
+
[1, 1, 1, 1, 1],
|
|
180
|
+
[1, 1, 2, 2, 2],
|
|
181
|
+
[1, 1, 1, 1, 1],
|
|
182
|
+
[1, 1, 1, 1, 1],
|
|
183
|
+
[1, 1, 1, 1, 1]
|
|
184
|
+
])
|
|
185
|
+
self.assertEqual(data.modified_range, (2, 14))
|
|
186
|
+
|
|
187
|
+
def test_repr(self):
|
|
188
|
+
array2d = [[1, 2], [3, 4]]
|
|
189
|
+
arrayrepr = repr(np.array(array2d))
|
|
190
|
+
array_id = (3, 4)
|
|
191
|
+
data = DataArray(preset_data=array2d)
|
|
192
|
+
|
|
193
|
+
self.assertEqual(repr(data), 'DataArray[2,2]:\n' + arrayrepr)
|
|
194
|
+
|
|
195
|
+
data.array_id = array_id
|
|
196
|
+
self.assertEqual(repr(data), 'DataArray[2,2]: ' + str(array_id) +
|
|
197
|
+
'\n' + arrayrepr)
|
|
198
|
+
|
|
199
|
+
def test_nest_empty(self):
|
|
200
|
+
data = DataArray()
|
|
201
|
+
|
|
202
|
+
self.assertEqual(data.shape, ())
|
|
203
|
+
|
|
204
|
+
mock_set_array = 'not really an array but we don\'t check'
|
|
205
|
+
mock_set_array2 = 'another one'
|
|
206
|
+
|
|
207
|
+
data.nest(2, action_index=44, set_array=mock_set_array)
|
|
208
|
+
data.nest(3, action_index=66, set_array=mock_set_array2)
|
|
209
|
+
|
|
210
|
+
# the array doesn't exist until you initialize it
|
|
211
|
+
self.assertIsNone(data.ndarray)
|
|
212
|
+
|
|
213
|
+
# but other attributes are set
|
|
214
|
+
self.assertEqual(data.shape, (3, 2))
|
|
215
|
+
self.assertEqual(data.action_indices, (66, 44))
|
|
216
|
+
self.assertEqual(data.set_arrays, (mock_set_array2, mock_set_array))
|
|
217
|
+
|
|
218
|
+
data.init_data()
|
|
219
|
+
self.assertEqual(data.ndarray.shape, (3, 2))
|
|
220
|
+
|
|
221
|
+
# after initializing data, you can't nest anymore because this isn't
|
|
222
|
+
# a preset array
|
|
223
|
+
with self.assertRaises(RuntimeError):
|
|
224
|
+
data.nest(4)
|
|
225
|
+
|
|
226
|
+
def test_nest_preset(self):
|
|
227
|
+
data = DataArray(preset_data=[1, 2])
|
|
228
|
+
data.nest(3)
|
|
229
|
+
self.assertEqual(data.shape, (3, 2))
|
|
230
|
+
self.assertEqual(data.ndarray.tolist(), [[1, 2]] * 3)
|
|
231
|
+
self.assertEqual(data.action_indices, ())
|
|
232
|
+
self.assertEqual(data.set_arrays, (data,))
|
|
233
|
+
|
|
234
|
+
# test that the modified range gets correctly set to
|
|
235
|
+
# (0, 2*3-1 = 5)
|
|
236
|
+
self.assertEqual(data.modified_range, (0, 5))
|
|
237
|
+
|
|
238
|
+
# you need a set array for all but the inner nesting
|
|
239
|
+
with self.assertRaises(TypeError):
|
|
240
|
+
data.nest(4)
|
|
241
|
+
|
|
242
|
+
def test_data_set_property(self):
|
|
243
|
+
data = DataArray(preset_data=[1, 2])
|
|
244
|
+
self.assertIsNone(data.data_set)
|
|
245
|
+
|
|
246
|
+
mock_data_set = 'pretend this is a DataSet, we don\'t check type'
|
|
247
|
+
mock_data_set2 = 'you can only assign to another after first clearing'
|
|
248
|
+
data.data_set = mock_data_set
|
|
249
|
+
self.assertEqual(data.data_set, mock_data_set)
|
|
250
|
+
|
|
251
|
+
with self.assertRaises(RuntimeError):
|
|
252
|
+
data.data_set = mock_data_set2
|
|
253
|
+
|
|
254
|
+
data.data_set = None
|
|
255
|
+
self.assertIsNone(data.data_set)
|
|
256
|
+
data.data_set = mock_data_set2
|
|
257
|
+
self.assertEqual(data.data_set, mock_data_set2)
|
|
258
|
+
|
|
259
|
+
def test_fraction_complete(self):
|
|
260
|
+
data = DataArray(shape=(5, 10))
|
|
261
|
+
self.assertIsNone(data.ndarray)
|
|
262
|
+
self.assertEqual(data.fraction_complete(), 0.0)
|
|
263
|
+
|
|
264
|
+
data.init_data()
|
|
265
|
+
self.assertEqual(data.fraction_complete(), 0.0)
|
|
266
|
+
|
|
267
|
+
# index = 1 * 10 + 7 - add 1 (for index 0) and you get 18
|
|
268
|
+
# each index is 2% of the total, so this is 36%
|
|
269
|
+
data[1, 7] = 1
|
|
270
|
+
self.assertEqual(data.fraction_complete(), 18/50)
|
|
271
|
+
|
|
272
|
+
# add a last_saved_index but modified_range is still bigger
|
|
273
|
+
data.mark_saved(13)
|
|
274
|
+
self.assertEqual(data.fraction_complete(), 18/50)
|
|
275
|
+
|
|
276
|
+
# now last_saved_index wins
|
|
277
|
+
data.mark_saved(19)
|
|
278
|
+
self.assertEqual(data.fraction_complete(), 20/50)
|
|
279
|
+
|
|
280
|
+
# now pretend we get more info from syncing
|
|
281
|
+
data.synced_index = 22
|
|
282
|
+
self.assertEqual(data.fraction_complete(), 23/50)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class TestLoadData(TestCase):
|
|
286
|
+
|
|
287
|
+
def setUp(self):
|
|
288
|
+
kill_processes()
|
|
289
|
+
|
|
290
|
+
def test_no_live_data(self):
|
|
291
|
+
# live data with no DataManager at all
|
|
292
|
+
with self.assertRaises(RuntimeError):
|
|
293
|
+
load_data()
|
|
294
|
+
self.assertEqual(len(active_children()), 0)
|
|
295
|
+
|
|
296
|
+
# now make a DataManager and try again
|
|
297
|
+
get_data_manager()
|
|
298
|
+
self.assertEqual(len(active_children()), 1)
|
|
299
|
+
# same result but different code path
|
|
300
|
+
with self.assertRaises(RuntimeError):
|
|
301
|
+
load_data()
|
|
302
|
+
|
|
303
|
+
def test_no_saved_data(self):
|
|
304
|
+
with self.assertRaises(IOError):
|
|
305
|
+
load_data('_no/such/file_')
|
|
306
|
+
|
|
307
|
+
def test_load_false(self):
|
|
308
|
+
with self.assertRaises(ValueError):
|
|
309
|
+
load_data(False)
|
|
310
|
+
|
|
311
|
+
def test_get_live(self):
|
|
312
|
+
loc = 'live from New York!'
|
|
313
|
+
|
|
314
|
+
class MockLive:
|
|
315
|
+
pass
|
|
316
|
+
|
|
317
|
+
live_data = MockLive()
|
|
318
|
+
|
|
319
|
+
dm = MockDataManager()
|
|
320
|
+
dm.location = loc
|
|
321
|
+
dm.live_data = live_data
|
|
322
|
+
|
|
323
|
+
data = load_data(data_manager=dm, location=loc)
|
|
324
|
+
self.assertEqual(data, live_data)
|
|
325
|
+
|
|
326
|
+
for nd in (None, NoData()):
|
|
327
|
+
dm.live_data = nd
|
|
328
|
+
with self.assertRaises(RuntimeError):
|
|
329
|
+
load_data(data_manager=dm, location=loc)
|
|
330
|
+
with self.assertRaises(RuntimeError):
|
|
331
|
+
load_data(data_manager=dm)
|
|
332
|
+
|
|
333
|
+
def test_get_read(self):
|
|
334
|
+
dm = MockDataManager()
|
|
335
|
+
dm.location = 'somewhere else'
|
|
336
|
+
|
|
337
|
+
data = load_data(formatter=MockFormatter(), data_manager=dm,
|
|
338
|
+
location='here!')
|
|
339
|
+
self.assertEqual(data.has_read_data, True)
|
|
340
|
+
self.assertEqual(data.has_read_metadata, True)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class TestDataSetMetaData(TestCase):
|
|
344
|
+
|
|
345
|
+
def test_snapshot(self):
|
|
346
|
+
data = new_data(location=False)
|
|
347
|
+
expected_snap = {
|
|
348
|
+
'__class__': 'qcodes.data.data_set.DataSet',
|
|
349
|
+
'location': False,
|
|
350
|
+
'arrays': {},
|
|
351
|
+
'formatter': 'qcodes.data.gnuplot_format.GNUPlotFormat',
|
|
352
|
+
}
|
|
353
|
+
snap = strip_qc(data.snapshot())
|
|
354
|
+
|
|
355
|
+
# handle io separately so we don't need to figure out our path
|
|
356
|
+
self.assertIn('DiskIO', snap['io'])
|
|
357
|
+
del snap['io']
|
|
358
|
+
self.assertEqual(snap, expected_snap)
|
|
359
|
+
|
|
360
|
+
# even though we removed io from the snapshot, it's still in .metadata
|
|
361
|
+
self.assertIn('io', data.metadata)
|
|
362
|
+
|
|
363
|
+
# then do the same transformations to metadata to check it too
|
|
364
|
+
del data.metadata['io']
|
|
365
|
+
strip_qc(data.metadata)
|
|
366
|
+
self.assertEqual(data.metadata, expected_snap)
|
|
367
|
+
|
|
368
|
+
# location is False so read_metadata should be a noop
|
|
369
|
+
data.metadata = {'food': 'Fried chicken'}
|
|
370
|
+
data.read_metadata()
|
|
371
|
+
self.assertEqual(data.metadata, {'food': 'Fried chicken'})
|
|
372
|
+
|
|
373
|
+
# snapshot should never delete things from metadata, only add or update
|
|
374
|
+
data.metadata['location'] = 'Idaho'
|
|
375
|
+
snap = strip_qc(data.snapshot())
|
|
376
|
+
expected_snap['food'] = 'Fried chicken'
|
|
377
|
+
del snap['io']
|
|
378
|
+
self.assertEqual(snap, expected_snap)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class TestNewData(TestCase):
|
|
382
|
+
|
|
383
|
+
@classmethod
|
|
384
|
+
def setUpClass(cls):
|
|
385
|
+
kill_processes()
|
|
386
|
+
cls.original_lp = DataSet.location_provider
|
|
387
|
+
|
|
388
|
+
@classmethod
|
|
389
|
+
def tearDownClass(cls):
|
|
390
|
+
DataSet.location_provider = cls.original_lp
|
|
391
|
+
|
|
392
|
+
def test_overwrite(self):
|
|
393
|
+
io = MatchIO([1])
|
|
394
|
+
|
|
395
|
+
with self.assertRaises(FileExistsError):
|
|
396
|
+
new_data(location='somewhere', io=io, data_manager=False)
|
|
397
|
+
|
|
398
|
+
data = new_data(location='somewhere', io=io, overwrite=True,
|
|
399
|
+
data_manager=False)
|
|
400
|
+
self.assertEqual(data.location, 'somewhere')
|
|
401
|
+
|
|
402
|
+
def test_mode_error(self):
|
|
403
|
+
with self.assertRaises(ValueError):
|
|
404
|
+
new_data(mode=DataMode.PUSH_TO_SERVER, data_manager=False)
|
|
405
|
+
|
|
406
|
+
def test_location_functions(self):
|
|
407
|
+
def my_location(io, record):
|
|
408
|
+
return 'data/{}'.format((record or {}).get('name') or 'LOOP!')
|
|
409
|
+
|
|
410
|
+
def my_location2(io, record):
|
|
411
|
+
name = (record or {}).get('name') or 'loop?'
|
|
412
|
+
return 'data/{}/folder'.format(name)
|
|
413
|
+
|
|
414
|
+
DataSet.location_provider = my_location
|
|
415
|
+
|
|
416
|
+
self.assertEqual(new_data(data_manager=False).location, 'data/LOOP!')
|
|
417
|
+
self.assertEqual(new_data(data_manager=False, name='cheese').location,
|
|
418
|
+
'data/cheese')
|
|
419
|
+
|
|
420
|
+
data = new_data(data_manager=False, location=my_location2)
|
|
421
|
+
self.assertEqual(data.location, 'data/loop?/folder')
|
|
422
|
+
data = new_data(data_manager=False, location=my_location2,
|
|
423
|
+
name='iceCream')
|
|
424
|
+
self.assertEqual(data.location, 'data/iceCream/folder')
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class TestDataSet(TestCase):
|
|
428
|
+
|
|
429
|
+
def tearDown(self):
|
|
430
|
+
kill_processes()
|
|
431
|
+
|
|
432
|
+
def test_constructor_errors(self):
|
|
433
|
+
# no location - only allowed with load_data
|
|
434
|
+
with self.assertRaises(ValueError):
|
|
435
|
+
DataSet()
|
|
436
|
+
# wrong type
|
|
437
|
+
with self.assertRaises(ValueError):
|
|
438
|
+
DataSet(location=42)
|
|
439
|
+
|
|
440
|
+
# OK to have location=False, but wrong mode
|
|
441
|
+
with self.assertRaises(ValueError):
|
|
442
|
+
DataSet(location=False, mode='happy')
|
|
443
|
+
|
|
444
|
+
@patch('qcodes.data.data_set.get_data_manager')
|
|
445
|
+
def test_from_server(self, gdm_mock):
|
|
446
|
+
mock_dm = MockDataManager()
|
|
447
|
+
gdm_mock.return_value = mock_dm
|
|
448
|
+
mock_dm.location = 'Mars'
|
|
449
|
+
mock_dm.live_data = MockLive()
|
|
450
|
+
|
|
451
|
+
# wrong location or False location - converts to local
|
|
452
|
+
data = DataSet(location='Jupiter', data_manager=True, mode=DataMode.PULL_FROM_SERVER)
|
|
453
|
+
self.assertEqual(data.mode, DataMode.LOCAL)
|
|
454
|
+
|
|
455
|
+
data = DataSet(location=False, data_manager=True, mode=DataMode.PULL_FROM_SERVER)
|
|
456
|
+
self.assertEqual(data.mode, DataMode.LOCAL)
|
|
457
|
+
|
|
458
|
+
# location matching server - stays in server mode
|
|
459
|
+
data = DataSet(location='Mars', data_manager=True, mode=DataMode.PULL_FROM_SERVER,
|
|
460
|
+
formatter=MockFormatter())
|
|
461
|
+
self.assertEqual(data.mode, DataMode.PULL_FROM_SERVER)
|
|
462
|
+
self.assertEqual(data.arrays, MockLive.arrays)
|
|
463
|
+
|
|
464
|
+
# cannot write except in LOCAL mode
|
|
465
|
+
with self.assertRaises(RuntimeError):
|
|
466
|
+
data.write()
|
|
467
|
+
|
|
468
|
+
# cannot finalize in PULL_FROM_SERVER mode
|
|
469
|
+
with self.assertRaises(RuntimeError):
|
|
470
|
+
data.finalize()
|
|
471
|
+
|
|
472
|
+
# now test when the server says it's not there anymore
|
|
473
|
+
mock_dm.location = 'Saturn'
|
|
474
|
+
data.sync()
|
|
475
|
+
self.assertEqual(data.mode, DataMode.LOCAL)
|
|
476
|
+
self.assertEqual(data.has_read_data, True)
|
|
477
|
+
|
|
478
|
+
# now it's LOCAL so we *can* write.
|
|
479
|
+
data.write()
|
|
480
|
+
self.assertEqual(data.has_written_data, True)
|
|
481
|
+
|
|
482
|
+
# location=False: write, read and sync are noops.
|
|
483
|
+
data.has_read_data = False
|
|
484
|
+
data.has_written_data = False
|
|
485
|
+
data.location = False
|
|
486
|
+
data.write()
|
|
487
|
+
data.read()
|
|
488
|
+
data.sync()
|
|
489
|
+
self.assertEqual(data.has_read_data, False)
|
|
490
|
+
self.assertEqual(data.has_written_data, False)
|
|
491
|
+
|
|
492
|
+
@patch('qcodes.data.data_set.get_data_manager')
|
|
493
|
+
def test_to_server(self, gdm_mock):
|
|
494
|
+
mock_dm = MockDataManager()
|
|
495
|
+
mock_dm.needs_restart = True
|
|
496
|
+
gdm_mock.return_value = mock_dm
|
|
497
|
+
|
|
498
|
+
data = DataSet(location='Venus', data_manager=True, mode=DataMode.PUSH_TO_SERVER)
|
|
499
|
+
self.assertEqual(mock_dm.needs_restart, False, data)
|
|
500
|
+
self.assertEqual(mock_dm.data_set, data)
|
|
501
|
+
self.assertEqual(data.data_manager, mock_dm)
|
|
502
|
+
self.assertEqual(data.mode, DataMode.PUSH_TO_SERVER)
|
|
503
|
+
|
|
504
|
+
# cannot write except in LOCAL mode
|
|
505
|
+
with self.assertRaises(RuntimeError):
|
|
506
|
+
data.write()
|
|
507
|
+
|
|
508
|
+
# now do what the DataServer does with this DataSet: init_on_server
|
|
509
|
+
# fails until there is an array
|
|
510
|
+
with self.assertRaises(RuntimeError):
|
|
511
|
+
data.init_on_server()
|
|
512
|
+
|
|
513
|
+
data.add_array(MockArray())
|
|
514
|
+
data.init_on_server()
|
|
515
|
+
self.assertEqual(data.noise.ready, True)
|
|
516
|
+
|
|
517
|
+
# we can only add a given array_id once
|
|
518
|
+
with self.assertRaises(ValueError):
|
|
519
|
+
data.add_array(MockArray())
|
|
520
|
+
|
|
521
|
+
def test_write_copy(self):
|
|
522
|
+
data = DataSet1D(location=False)
|
|
523
|
+
mockbase = os.path.abspath('some_folder')
|
|
524
|
+
data.io = DiskIO(mockbase)
|
|
525
|
+
|
|
526
|
+
mr = (2, 3)
|
|
527
|
+
mr_full = (0, 4)
|
|
528
|
+
lsi = 1
|
|
529
|
+
data.x_set.modified_range = mr
|
|
530
|
+
data.y.modified_range = mr
|
|
531
|
+
data.x_set.last_saved_index = lsi
|
|
532
|
+
data.y.last_saved_index = lsi
|
|
533
|
+
|
|
534
|
+
with self.assertRaises(TypeError):
|
|
535
|
+
data.write_copy()
|
|
536
|
+
|
|
537
|
+
with self.assertRaises(TypeError):
|
|
538
|
+
data.write_copy(path='some/path', io_manager=DiskIO('.'))
|
|
539
|
+
|
|
540
|
+
with self.assertRaises(TypeError):
|
|
541
|
+
data.write_copy(path='some/path', location='something/else')
|
|
542
|
+
|
|
543
|
+
data.formatter = RecordingMockFormatter()
|
|
544
|
+
data.write_copy(path='/some/abs/path')
|
|
545
|
+
self.assertEqual(data.formatter.write_calls,
|
|
546
|
+
[(None, '/some/abs/path')])
|
|
547
|
+
self.assertEqual(data.formatter.write_metadata_calls,
|
|
548
|
+
[(None, '/some/abs/path', False)])
|
|
549
|
+
# check that the formatter gets called as if nothing has been saved
|
|
550
|
+
self.assertEqual(data.formatter.modified_ranges,
|
|
551
|
+
[{'x_set': mr_full, 'y': mr_full}])
|
|
552
|
+
self.assertEqual(data.formatter.last_saved_indices,
|
|
553
|
+
[{'x_set': None, 'y': None}])
|
|
554
|
+
# but the dataset afterward has its original mods back
|
|
555
|
+
self.assertEqual(data.x_set.modified_range, mr)
|
|
556
|
+
self.assertEqual(data.y.modified_range, mr)
|
|
557
|
+
self.assertEqual(data.x_set.last_saved_index, lsi)
|
|
558
|
+
self.assertEqual(data.y.last_saved_index, lsi)
|
|
559
|
+
|
|
560
|
+
# recreate the formatter to clear the calls attributes
|
|
561
|
+
data.formatter = RecordingMockFormatter()
|
|
562
|
+
data.write_copy(location='some/rel/path')
|
|
563
|
+
self.assertEqual(data.formatter.write_calls,
|
|
564
|
+
[(mockbase, 'some/rel/path')])
|
|
565
|
+
self.assertEqual(data.formatter.write_metadata_calls,
|
|
566
|
+
[(mockbase, 'some/rel/path', False)])
|
|
567
|
+
|
|
568
|
+
mockbase2 = os.path.abspath('some/other/folder')
|
|
569
|
+
io2 = DiskIO(mockbase2)
|
|
570
|
+
|
|
571
|
+
with self.assertRaises(ValueError):
|
|
572
|
+
# if location=False we need to specify it in write_copy
|
|
573
|
+
data.write_copy(io_manager=io2)
|
|
574
|
+
|
|
575
|
+
data.location = 'yet/another/path'
|
|
576
|
+
data.formatter = RecordingMockFormatter()
|
|
577
|
+
data.write_copy(io_manager=io2)
|
|
578
|
+
self.assertEqual(data.formatter.write_calls,
|
|
579
|
+
[(mockbase2, 'yet/another/path')])
|
|
580
|
+
self.assertEqual(data.formatter.write_metadata_calls,
|
|
581
|
+
[(mockbase2, 'yet/another/path', False)])
|
|
582
|
+
|
|
583
|
+
def test_pickle_dataset(self):
|
|
584
|
+
# Test pickling of DataSet object
|
|
585
|
+
# If the data_manager is set to None, then the object should pickle.
|
|
586
|
+
m = DataSet2D()
|
|
587
|
+
pickle.dumps(m)
|
|
588
|
+
|
|
589
|
+
def test_fraction_complete(self):
|
|
590
|
+
empty_data = new_data(arrays=(), location=False)
|
|
591
|
+
self.assertEqual(empty_data.fraction_complete(), 0.0)
|
|
592
|
+
|
|
593
|
+
data = DataSetCombined(location=False)
|
|
594
|
+
self.assertEqual(data.fraction_complete(), 1.0)
|
|
595
|
+
|
|
596
|
+
# alter only the measured arrays, check that only these are used
|
|
597
|
+
# to calculate fraction_complete
|
|
598
|
+
data.y1.modified_range = (0, 0) # 1 of 2
|
|
599
|
+
data.y2.modified_range = (0, 0) # 1 of 2
|
|
600
|
+
data.z1.modified_range = (0, 2) # 3 of 6
|
|
601
|
+
data.z2.modified_range = (0, 2) # 3 of 6
|
|
602
|
+
self.assertEqual(data.fraction_complete(), 0.5)
|
|
603
|
+
|
|
604
|
+
# mark more things complete using last_saved_index and synced_index
|
|
605
|
+
data.y1.last_saved_index = 1 # 2 of 2
|
|
606
|
+
data.z1.synced_index = 5 # 6 of 6
|
|
607
|
+
self.assertEqual(data.fraction_complete(), 0.75)
|
|
608
|
+
|
|
609
|
+
def mock_sync(self):
|
|
610
|
+
# import pdb; pdb.set_trace()
|
|
611
|
+
i = self.sync_index
|
|
612
|
+
self.syncing_array[i] = i
|
|
613
|
+
self.sync_index = i + 1
|
|
614
|
+
return self.sync_index < self.syncing_array.size
|
|
615
|
+
|
|
616
|
+
def failing_func(self):
|
|
617
|
+
raise RuntimeError('it is called failing_func for a reason!')
|
|
618
|
+
|
|
619
|
+
def logging_func(self):
|
|
620
|
+
logging.info('background at index {}'.format(self.sync_index))
|
|
621
|
+
|
|
622
|
+
def test_complete(self):
|
|
623
|
+
array = DataArray(name='y', shape=(5,))
|
|
624
|
+
array.init_data()
|
|
625
|
+
data = new_data(arrays=(array,), location=False)
|
|
626
|
+
self.syncing_array = array
|
|
627
|
+
self.sync_index = 0
|
|
628
|
+
data.sync = self.mock_sync
|
|
629
|
+
bf = DataSet.background_functions
|
|
630
|
+
bf['fail'] = self.failing_func
|
|
631
|
+
bf['log'] = self.logging_func
|
|
632
|
+
|
|
633
|
+
with LogCapture() as logs:
|
|
634
|
+
# grab info and warnings but not debug messages
|
|
635
|
+
logging.getLogger().setLevel(logging.INFO)
|
|
636
|
+
data.complete(delay=0.001)
|
|
637
|
+
|
|
638
|
+
logs = logs.value
|
|
639
|
+
|
|
640
|
+
expected_logs = [
|
|
641
|
+
'waiting for DataSet <False> to complete',
|
|
642
|
+
'DataSet: 0% complete',
|
|
643
|
+
'RuntimeError: it is called failing_func for a reason!',
|
|
644
|
+
'background at index 1',
|
|
645
|
+
'DataSet: 20% complete',
|
|
646
|
+
'RuntimeError: it is called failing_func for a reason!',
|
|
647
|
+
'background function fail failed twice in a row, removing it',
|
|
648
|
+
'background at index 2',
|
|
649
|
+
'DataSet: 40% complete',
|
|
650
|
+
'background at index 3',
|
|
651
|
+
'DataSet: 60% complete',
|
|
652
|
+
'background at index 4',
|
|
653
|
+
'DataSet: 80% complete',
|
|
654
|
+
'background at index 5',
|
|
655
|
+
'DataSet <False> is complete'
|
|
656
|
+
]
|
|
657
|
+
|
|
658
|
+
log_index = 0
|
|
659
|
+
for line in expected_logs:
|
|
660
|
+
self.assertIn(line, logs, logs)
|
|
661
|
+
try:
|
|
662
|
+
log_index_new = logs.index(line, log_index)
|
|
663
|
+
except ValueError:
|
|
664
|
+
raise ValueError('line {} not found after {} in: \n {}'.format(
|
|
665
|
+
line, log_index, logs))
|
|
666
|
+
self.assertTrue(log_index_new >= log_index, logs)
|
|
667
|
+
log_index = log_index_new + len(line) + 1 # +1 for \n
|
|
668
|
+
self.assertEqual(log_index, len(logs), logs)
|