From 02d189ff3f7121e764f6a3ca6d106d2daaca6135 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 28 Oct 2021 16:09:16 +0200 Subject: [PATCH] Update CI (#773) * add 3.9 to CI; make hickle optional * improve error message * remove tests for deprecated methods * remove deprecated method * fix ci * fix ci * update changelog Co-authored-by: Pieter Eendebak --- .travis.yml | 5 ++- CHANGELOG.md | 2 + docs/notebooks/qtt_example.py | 40 +++++++++---------- setup.py | 3 +- src/qtt/data.py | 11 +++-- src/qtt/gui/live_plotting.py | 34 ++++++++-------- .../unittests/measurements/test_storage.py | 31 -------------- 7 files changed, 51 insertions(+), 75 deletions(-) delete mode 100644 src/tests/unittests/measurements/test_storage.py diff --git a/.travis.yml b/.travis.yml index 892c11055..69d95921c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ cache: pip matrix: include: - - name: Minimal installation 3.8 - python: 3.8 + - name: Minimal installation 3.9 + python: 3.9 sudo: true dist: xenial env: QT_QPA_PLATFORM=offscreen @@ -20,6 +20,7 @@ matrix: - xvfb install: + - sudo apt-get install libhdf5-dev - pip install coveralls - pip install --upgrade pip - pip install -e . diff --git a/CHANGELOG.md b/CHANGELOG.md index f65617e64..78564f24b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,11 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add method to combine legends of multiple matplotlib axes (#782) - Functionality plot onto a matplotlib Axes object (#785) - Context manager 'restore_at_exit' in the 'VirtualDAC' object (#792) +- Added python 3.9 support (#773) ### Changed - Improve sine fitting (#762) - The 'dataset_labels' method can handle both DataSet's DataArray's (#771) +- Hickle is now optional for installation (#773) ### Removed diff --git a/docs/notebooks/qtt_example.py b/docs/notebooks/qtt_example.py index f3c0d3cee..f99db8fde 100644 --- a/docs/notebooks/qtt_example.py +++ b/docs/notebooks/qtt_example.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Example script to show QTT capabilities The script should be executed from an interactive environment such as Spyder. @@ -8,23 +7,24 @@ """ # %% Load packages -import numpy as np -import matplotlib.pyplot as plt + import tempfile +import time from collections import OrderedDict -import pyqtgraph +import matplotlib.pyplot as plt +import numpy as np +import pyqtgraph import qcodes from qcodes.data.data_set import DataSet + import qtt -from qtt.gui.parameterviewer import createParameterWidget -from qtt.algorithms.gatesweep import analyseGateSweep -from qtt.measurements.scans import scanjob_t -from qtt.instrument_drivers.virtual_gates import VirtualGates -from qtt import save_state import qtt.measurements.videomode - import qtt.simulation.virtual_dot_array +from qtt.algorithms.gatesweep import analyseGateSweep +from qtt.gui.parameterviewer import createParameterWidget +from qtt.instrument_drivers.virtual_gates import VirtualGates +from qtt.measurements.scans import scanjob_t _ = pyqtgraph.mkQApp() datadir = tempfile.mkdtemp(prefix='qtt_example') @@ -47,8 +47,7 @@ # %% Setup measurement windows - -mwindows = qtt.gui.live_plotting.setupMeasurementWindows(station, create_parameter_widget=False) +mwindows = qtt.gui.live_plotting.setupMeasurementWindows(station, create_parameter_widget=False, qtplot_remote=False) pv = createParameterWidget([gates, ]) logviewer = qtt.gui.dataviewer.DataViewer() @@ -64,17 +63,14 @@ param_left = station.model.bottomgates[0] param_right = station.model.bottomgates[-1] scanjob = scanjob_t({'sweepdata': dict({'param': param_right, 'start': -500, 'end': 0, - 'step': .8, 'wait_time': 3e-3}), 'minstrument': ['keithley3.amplitude']}) + 'step': .8, 'wait_time': 2.2e-3}), 'minstrument': ['keithley3.amplitude']}) data1d = qtt.measurements.scans.scan1D(station, scanjob, location=None, verbose=1) -# %% Save the current state of the system to disk - -save_state(station) - # %% Print the scanned data -print(data1d.default_parameter_name()) +print(data1d) +print(f'default parameter name in dataset: {data1d.default_parameter_name()}') # %% Make a 2D scan start = -500 @@ -158,7 +154,8 @@ # %% Close all GUI elements if not qtt.utilities.tools.is_spyder_environment(): - print('close all GUI elements') + print('closing all GUI elements') + time.sleep(.5) vm.close() vm_virtual.close() plt.close('all') @@ -166,4 +163,7 @@ logviewer.close() qtt.gui.live_plotting.liveplotwindow.win.close() - print('close all GUI elements: done') + pyqtgraph.mkQApp().processEvents() + + print('closed all GUI elements: done') + time.sleep(.5) diff --git a/setup.py b/setup.py index f36100640..84063f505 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def get_package_data(root_dir): tests_require = ['coverage', 'jupyter', 'mypy', 'types-redis', 'types-python-dateutil', 'pytest'] install_requires = [ - 'apscheduler', 'attrs', 'dulwich', 'h5py<3.0', 'hickle', 'IPython>=0.1', 'jupyter', 'lmfit', 'matplotlib>=3.0', + 'apscheduler', 'attrs', 'dulwich', 'h5py', 'IPython>=0.1', 'jupyter', 'lmfit', 'matplotlib>=3.0', 'numdifftools', 'numpy>=1.15', 'opencv-python', 'pandas', 'PyQt5', 'pyqtgraph', 'pyvisa', 'pyzmqrpc', 'qcodes>=0.23.0', 'qcodes-contrib-drivers', 'qilib', 'qtpy', 'qupulse', 'redis', 'scipy', 'scikit-image', 'shapely', 'sympy', 'imageio' @@ -67,6 +67,7 @@ def get_package_data(root_dir): 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Scientific/Engineering' ], license='MIT', diff --git a/src/qtt/data.py b/src/qtt/data.py index 6ccd1188f..f9e20cc49 100644 --- a/src/qtt/data.py +++ b/src/qtt/data.py @@ -30,7 +30,7 @@ def load_example_dataset(filename: str, verbose: int = 0) -> Optional[DataSet]: Returns: Example dataset or None of no dataset can be found """ - exampledatadir = os.path.join(qtt.__path__[0], 'exampledata') # type: ignore # mypy issue #1422 + exampledatadir = os.path.join(qtt.__path__[0], 'exampledata') # type: ignore # mypy issue #1422 dataset = qtt.data.load_dataset(os.path.join(exampledatadir, filename), verbose=verbose) return dataset @@ -165,8 +165,12 @@ def load_dataset(location, io=None, verbose=0): formatters = [DataSet.default_formatter] from qcodes.data.hdf5_format import HDF5FormatMetadata - from qcodes.data.hdf5_format_hickle import HDF5FormatHickle - formatters += [HDF5FormatHickle(), HDF5FormatMetadata()] + formatters += [HDF5FormatMetadata()] + try: + from qcodes.data.hdf5_format_hickle import HDF5FormatHickle + formatters += [HDF5FormatHickle()] + except ImportError as ex: + logging.info(f'HDF5FormatHickle not available {ex}') from qcodes.data.hdf5_format import HDF5Format formatters += [HDF5Format()] @@ -912,7 +916,6 @@ def _data_extension(): def load_data(mfile: str): """ Load data from specified file """ - # return hickle.load(mfile) ext = _data_extension() if ext is not None: if not mfile.endswith(ext): diff --git a/src/qtt/gui/live_plotting.py b/src/qtt/gui/live_plotting.py index 2178868af..ade7e0904 100644 --- a/src/qtt/gui/live_plotting.py +++ b/src/qtt/gui/live_plotting.py @@ -1,18 +1,20 @@ # %% Load packages -import time import logging -import numpy as np +import time from functools import partial -import qtpy.QtWidgets as QtWidgets -import qtpy.QtCore as QtCore -from qtpy.QtCore import Signal -import pyqtgraph as pg + +import numpy as np import pyqtgraph +import pyqtgraph as pg import pyqtgraph.multiprocess as mp import qcodes +import qtpy.QtCore as QtCore +import qtpy.QtWidgets as QtWidgets +from qtpy.QtCore import Signal + import qtt -from qtt import pgeometry import qtt.algorithms.generic +from qtt import pgeometry # %% Static variables @@ -247,14 +249,14 @@ def start_measurement_control(doexec=False): try: - import qtt.gui.parameterviewer - import qtt.gui - from qtt.utilities.tools import monitorSizes from qcodes.plots.pyqtgraph import QtPlot + import qtt.gui + import qtt.gui.parameterviewer + from qtt.utilities.tools import monitorSizes def setupMeasurementWindows(station=None, create_parameter_widget=True, - ilist=None): + ilist=None, qtplot_remote=True): """ Create liveplot window and parameter widget (optional) @@ -262,6 +264,7 @@ def setupMeasurementWindows(station=None, create_parameter_widget=True, station (QCoDeS station): station with instruments create_parameter_widget (bool): if True create ParameterWidget ilist (None or list): list of instruments to add to ParameterWidget + qtplot_remote (bool): If True, then use remote plotting Returns: dict: created gui objects """ @@ -277,7 +280,7 @@ def setupMeasurementWindows(station=None, create_parameter_widget=True, w.setGeometry(vv[0] + vv[2] - 400 - 300, vv[1], 300, 600) windows['parameterviewer'] = w - plotQ = QtPlot(window_title='Live plot', interval=.5) + plotQ = QtPlot(window_title='Live plot', interval=.5, remote=qtplot_remote) plotQ.setGeometry(vv[0] + vv[2] - 600, vv[1] + vv[3] - 400, 600, 400) plotQ.update() @@ -430,7 +433,7 @@ def __init__( self.fps = pgeometry.fps_t(nn=6) self.datafunction = datafunction self.datafunction_result = None - self.plot_dimension=plot_dimension + self.plot_dimension = plot_dimension self.alpha = alpha if is1dscan is None: is1dscan = ( @@ -691,7 +694,7 @@ def startreadout(self, callback=None, rate=30, maxidx=None): self.maxidx = maxidx if callback is not None: self.datafunction = callback - self.timer.start( int(1000 * (1. / rate)) ) + self.timer.start(int(1000 * (1. / rate))) if self.verbose: print('live_plotting: start readout: rate %.1f Hz' % rate) @@ -722,6 +725,3 @@ def __call__(self): lt.semiLine(data_reshaped, [self.nx / 2, self.nx / 2], np.deg2rad(self.q()), w=2, l=self.nx / 4, H=3) return data_reshaped - - - diff --git a/src/tests/unittests/measurements/test_storage.py b/src/tests/unittests/measurements/test_storage.py deleted file mode 100644 index b576c0e62..000000000 --- a/src/tests/unittests/measurements/test_storage.py +++ /dev/null @@ -1,31 +0,0 @@ -# %% -import qtt.simulation.virtual_dot_array -import tempfile -from qtt.instrument_drivers.virtual_gates import VirtualGates -from qtt.measurements.storage import save_state, load_state -from unittest import TestCase -# %% - - -class TestStorage(TestCase): - - def test_storage(self, verbose=0): - station = qtt.simulation.virtual_dot_array.initialize(reinit=True, nr_dots=2, maxelectrons=2, verbose=verbose) - v_gates = VirtualGates('virtual_gates_load_save_state', station.gates, {'vP1': {'P1': 1, 'P2': .1}, - 'vP2': {'P1': .2, 'P2': 1.}}) - - before_crosscap_map = v_gates.get_crosscap_map() - before_crosscap_map_inv = v_gates.get_crosscap_map_inv() - - tmp_file = tempfile.mkstemp()[1] - tag = save_state(station, virtual_gates=v_gates, verbose=verbose, statefile=tmp_file) - _, virtual_gates_loaded = load_state(station=station, tag=tag, verbose=verbose, statefile=tmp_file) - - after_crosscap_map = virtual_gates_loaded.get_crosscap_map() - after_crosscap_map_inv = virtual_gates_loaded.get_crosscap_map_inv() - - self.assertDictEqual(before_crosscap_map, after_crosscap_map) - self.assertDictEqual(before_crosscap_map_inv, after_crosscap_map_inv) - - virtual_gates_loaded.close() - v_gates.close()