Dev/pyctbgui merge (#960)

* added empty c extension

* added rotation to the decoding

* added color map, options and findex

* minor

* move checks to before acquisition

* added pixel map based decoder

* cleanup

* no thread creation for single thread processing

* added rotation and test to compare

* allow high and low water mark for zmq (also buffer size) for fast readouts

* removed roatation during decoding

* added Transpose to image and invert Y False to invert it

* retains the zoomed state after the first image of gui, catch and display exception if no detector connected

* moved start frame to dockable widget, removed extra frame number label, moved current measurement also to dockable widget, hide frame plot entirely when showing patternviewer

* first image dependin on which plot

* remember settings of main window size and position, dockewidget if docked, its size and posisiotn as well, then update it next time the gui is opened

* change in comment

* using c decoder for moench 04 and matterhorn

* catch exception from invalid image from decoder

* clean up

* update row and col when choosing image type, neeeded to show values

* fix for previous PR

* disable resetting colormap values
keep the range selected for every new acquisition

* fix typos + tested on virtual matterhorn

* minor print

* refactored Slow ADCs Tab

* refactored DAC tab

* refactored power supplies

* refactored signals tab

* refactored transceiver tab

* fix typo

* fix typo2

* remove commented code

* delete commented code

* delete commented code

* delete commented signals code

* remove commented code for transceiver tab

* refactor adc tab

* refactor Pattern Tab

* Refactor transceivers tab (PR#5) (#118)

* refactored transceiver tab

* remove commented code for transceiver tab

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>

* refactor adc tab (PR#6) (#119)


* refactor adc tab

* refactored Plot and Acquisition Tabs

* fix the regression issue

* restructure project files

* applying singleton and renaming tabs to services

* working install using pip

* applies singleton to tab classes and remove CI erros

* added pyzmq and pillow

* remove the singleton implementation and keep changes

* fix merge errors in mainWindow

* moved misplaced init file

* rename service to tab

* reorganize imports

* iterate over tabs

* reorder tabs

* add slowadc to the list

* saving changes (buggy)
power supply ui not showing in the gui

* split power supply tab

* fixed tests

* add hardcoded values to defines file

* fix error

* separate power supply

* fix errors for powerSuppliesTab

* split dacs

* split slow adcs

* split signals tab

* added tests for bit_utils

* add slowAdc class to defines

* split transceiver ui file

* split adc.ui

* split pattern ui file

* split plot and acquisition ui file

* added basic test for parsing bit names

* removed redundant code in read_alias_file

* fix dacs ui position

* testing for correct exception

* cmd and args at split

* group radio buttons

* fix comments from PR#1

* show legend

* added python version and dev requirements to setup.py

* fix dac issue

* moved _decoder into pkg

* added inplace build

* removed clear

* fixed dependencies

* make tests run without slsdet

* updated name of action

* define colcount

* fixed loading of alias file

* add yapf and ruff

* apply formatting

* fix E and F rules

* add more ruff rules

* change variable name

* squashing gh debugging commits and add pre-commit

* update label values to mv units

* add hook for yapf

* reconfigure yapf precommit hook

* add format and check_format to makefile

* change gh actions

* update readme

* added check_format

* WIP

* added linting in github action

* updated readme]

* add more control for color choice

* remove useless file

* fix un-updated line after refactoring Defines
BIT0_31_MASK is not found in Defines.signals

* visually improve the interface

* fix last commit

* add only selected plots for legend

* add hide legend button

* change hide legend to show legend
checkbox show legend is checked by default

* add support for saving in numpy

* solve conversations

* fix acq index offset

* fix browse button in pattern error

* fix other browse button errors

* finish tests and add usage.md

* remove buffer

* add file,numpy-like interface and tests

* remove useless .npy files

* subscriptible npz files

* remove useless files

* remove repetetive tests

* save changes

* add mode r+, add with support,remove logging

* remove offset of acqIndex between raw and numpy saving

* fix only saving last frame

* save signals of multiple devices

* add comments and move condition for clearer code

* fix bug when vieweing pattern file

* iterate over enabled and plotted plots

* add padestal substraction to transceiver and analog data

* init pedestal frames to detector.frames

* restore old exception

* add pedestal substraction for digital signals

* remove frames spinbox from plotTab

* remove comments and use str instead of Path

* avoid saving all frames

* correct exception and log error's trace

* add gui tests

* add waveform test

* add pedestal test

* refactor by using fixtures

* add tests for moench analog and pattern

* add pytest-qt to dependencies

* add save and load gui parameters

* remove nohup file

* fix old bug IndexError

* save plot type

* a

* handle canceling load, loading matterhorn pedestal for moench

* remove comparing .png files for pattern test

* save plot type

* red error on status bar when shape mismatch for loaded pedestal

* fix makefile and docstrings

* fix PRs conversation

* move code into different function

* fix wrong function names for power supply

* removed old ctbgui

* removed unnecessary files

---------

Co-authored-by: Erik Frojdh <erik.frojdh@gmail.com>
Co-authored-by: Braham Bechir <braham_b@pc11979.psi.ch>
Co-authored-by: Bechir <bechir.braham@psi.ch>
Co-authored-by: Bechir <bechir.brahem420@gmail.com>
This commit is contained in:
2024-09-10 16:00:04 +02:00
committed by GitHub
parent c6477e0ed6
commit 5b61ff24bb
93 changed files with 25399 additions and 7292 deletions

View File

View File

@@ -0,0 +1,11 @@
import pytest
from pyctbgui.ui import MainWindow
@pytest.fixture(scope='package')
def main():
main = MainWindow()
main.show()
yield main
main.close()

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,232 @@
patword 0x0000 0x000000006b2e8001
patword 0x0001 0x000000006b2e8001
patword 0x0002 0x000000006b2e8001
patword 0x0003 0x000000006b2e8001
patword 0x0004 0x000000006b2e8001
patword 0x0005 0x000000006b2e8001
patword 0x0006 0x000000006b2e8001
patword 0x0007 0x000000006b2e8001
patword 0x0008 0x000000006b2e8001
patword 0x0009 0x000000006b2e8001
patword 0x000a 0x000000006b2e8001
patword 0x000b 0x000000006b2e8001
patword 0x000c 0x00000000692e8001
patword 0x000d 0x00000000692e8001
patword 0x000e 0x00000000692e8001
patword 0x000f 0x00000000692e8001
patword 0x0010 0x00000000692e8001
patword 0x0011 0x00000000692e8001
patword 0x0012 0x00000000692e8001
patword 0x0013 0x00000000692e8001
patword 0x0014 0x00000000692e8001
patword 0x0015 0x00000000692e8001
patword 0x0016 0x00000000682e8001
patword 0x0017 0x00000000682e8001
patword 0x0018 0x00000000682e8001
patword 0x0019 0x00000000682e8001
patword 0x001a 0x00000000482c8001
patword 0x001b 0x00000000482c8001
patword 0x001c 0x00000000482c8001
patword 0x001d 0x00000000482c8001
patword 0x001e 0x00000000482c8001
patword 0x001f 0x00000000482c8001
patword 0x0020 0x00000000482c8001
patword 0x0021 0x00000000482c8001
patword 0x0022 0x00000000482c8001
patword 0x0023 0x00000000482c8001
patword 0x0024 0x00000000482c8001
patword 0x0025 0x00000000482c8001
patword 0x0026 0x00000000482c8001
patword 0x0027 0x00000000482c8001
patword 0x0028 0x00000000482c8001
patword 0x0029 0x00000000482c8001
patword 0x002a 0x00000000482c8001
patword 0x002b 0x00000000482c8001
patword 0x002c 0x00000000482c8001
patword 0x002d 0x00000000482c8001
patword 0x002e 0x00000000582c8001
patword 0x002f 0x00000000582c8001
patword 0x0030 0x00000000582c8001
patword 0x0031 0x00000000582c8001
patword 0x0032 0x00000000582c8001
patword 0x0033 0x00000000582c8001
patword 0x0034 0x00000000582c8001
patword 0x0035 0x00000000582c8001
patword 0x0036 0x00000000582c8001
patword 0x0037 0x00000000582c8001
patword 0x0038 0x00000000582c8001
patword 0x0039 0x00000000582c8001
patword 0x003a 0x00000000582c8001
patword 0x003b 0x00000000582c8001
patword 0x003c 0x00000000582c8001
patword 0x003d 0x00000000582c8001
patword 0x003e 0x00000000582c8001
patword 0x003f 0x00000000582c8001
patword 0x0040 0x00000000582c8001
patword 0x0041 0x00000000582c8001
patword 0x0042 0x00000000582c9011
patword 0x0043 0x00000000582c9011
patword 0x0044 0x00000000582c8001
patword 0x0045 0x00000000582c8001
patword 0x0046 0x00000000582c8001
patword 0x0047 0x00000000582c8001
patword 0x0048 0x00000000582c8001
patword 0x0049 0x00000000582c8001
patword 0x004a 0x00000000582c8001
patword 0x004b 0x00000000582c8001
patword 0x004c 0x00000000582c8001
patword 0x004d 0x00000000582c8001
patword 0x004e 0x00000000582c8001
patword 0x004f 0x00000000582c8001
patword 0x0050 0x00000000582c8001
patword 0x0051 0x00000000582c8001
patword 0x0052 0x00000000582c8001
patword 0x0053 0x00000000582c8001
patword 0x0054 0x00000000582c8001
patword 0x0055 0x00000000582c8001
patword 0x0056 0x00000000582c8001
patword 0x0057 0x00000000582c8001
patword 0x0058 0x00000000582c8001
patword 0x0059 0x00000000582c8001
patword 0x005a 0x00000000582c8041
patword 0x005b 0x00000000582c8041
patword 0x005c 0x00000000582c8141
patword 0x005d 0x00000000582c8041
patword 0x005e 0x00000000582c8041
patword 0x005f 0x00000000582c8041
patword 0x0060 0x00000000582c8041
patword 0x0061 0x00000000582c8041
patword 0x0062 0x00000000582c8041
patword 0x0063 0x00000000582c8041
patword 0x0064 0x00000000582c8041
patword 0x0065 0x00000000582c8041
patword 0x0066 0x00000000582c8041
patword 0x0067 0x00000000582c8041
patword 0x0068 0x00000000582c8041
patword 0x0069 0x00000000582c8041
patword 0x006a 0x00000000582c8041
patword 0x006b 0x00000000582c8041
patword 0x006c 0x00000000582c8041
patword 0x006d 0x00000000582c8041
patword 0x006e 0x00000000582c8041
patword 0x006f 0x00000000582c8041
patword 0x0070 0x00000000582c8041
patword 0x0071 0x00000000582c8041
patword 0x0072 0x00000000582c8041
patword 0x0073 0x00000000582c8041
patword 0x0074 0x00000000d82c8941
patword 0x0075 0x00000000d82c8041
patword 0x0076 0x00000000582c8001
patword 0x0077 0x00000000582c8001
patword 0x0078 0xc0000000582c8001
patword 0x0079 0xc0000000582c8801
patword 0x007a 0xc0000000582c8001
patword 0x007b 0xc0000000582c8801
patword 0x007c 0xc0000000582c8001
patword 0x007d 0xc0000000582c8801
patword 0x007e 0xc0000000582c8001
patword 0x007f 0xc0000000582c8801
patword 0x0080 0xc0000000582c8001
patword 0x0081 0xc0000000582c8801
patword 0x0082 0xc0000000582c8001
patword 0x0083 0xc0000000582c8801
patword 0x0084 0xc0000000582c8001
patword 0x0085 0xc0000000582c8801
patword 0x0086 0xc0000000582c8001
patword 0x0087 0xc0000000582c8801
patword 0x0088 0xc0000000582c8001
patword 0x0089 0xc0000000582c8801
patword 0x008a 0xc0000000582c8001
patword 0x008b 0xc0000000582c8801
patword 0x008c 0xc0000000582c8001
patword 0x008d 0xc0000000582c8801
patword 0x008e 0xc0000000582c8001
patword 0x008f 0xc0000000582c8801
patword 0x0090 0xc0000000582c8001
patword 0x0091 0xc0000000582c8901
patword 0x0092 0xc0000000582c8001
patword 0x0093 0xc0000000582c8801
patword 0x0094 0xc0000000582c8001
patword 0x0095 0xc0000000582c8801
patword 0x0096 0xc0000000582c8001
patword 0x0097 0xc0000000582c8801
patword 0x0098 0xc0000000582c8001
patword 0x0099 0xc0000000582c8801
patword 0x009a 0xc0000000582c8001
patword 0x009b 0xc0000000582c8801
patword 0x009c 0xc0000000582c8001
patword 0x009d 0xc0000000582c8801
patword 0x009e 0xc0000000582c8001
patword 0x009f 0xc0000000582c8801
patword 0x00a0 0xc0000000582c8001
patword 0x00a1 0xc0000000582c8801
patword 0x00a2 0xc0000000582c8001
patword 0x00a3 0xc0000000582c8801
patword 0x00a4 0xc0000000582c8001
patword 0x00a5 0xc0000000582c8801
patword 0x00a6 0xc0000000582c8001
patword 0x00a7 0xc0000000582c8801
patword 0x00a8 0xc0000000582c8001
patword 0x00a9 0xc0000000d82c8901
patword 0x00aa 0xc0000000d82c8001
patword 0x00ab 0xc0000000582c8801
patword 0x00ac 0xc0000000582c8001
patword 0x00ad 0xc0000000582c8801
patword 0x00ae 0xc0000000582c8001
patword 0x00af 0xc0000000582c8801
patword 0x00b0 0xc0000000582c8001
patword 0x00b1 0xc0000000582c8801
patword 0x00b2 0xc0000000582c8001
patword 0x00b3 0xc0000000582c8801
patword 0x00b4 0xc0000000582c8001
patword 0x00b5 0xc0000000582c8801
patword 0x00b6 0xc0000000582c8001
patword 0x00b7 0xc0000000582c8801
patword 0x00b8 0xc0000000582c8001
patword 0x00b9 0xc0000000582c8801
patword 0x00ba 0xc0000000582c8001
patword 0x00bb 0xc0000000582c8801
patword 0x00bc 0xc0000000582c8001
patword 0x00bd 0xc0000000582c8801
patword 0x00be 0xc0000000582c8001
patword 0x00bf 0xc0000000582c8801
patword 0x00c0 0xc0000000582c8001
patword 0x00c1 0xc0000000582c8801
patword 0x00c2 0xc0000000582c8001
patword 0x00c3 0xc0000000582c8901
patword 0x00c4 0xc0000000582c8001
patword 0x00c5 0xc0000000582c8801
patword 0x00c6 0xc0000000582c8001
patword 0x00c7 0xc0000000582c8801
patword 0x00c8 0xc0000000582c8001
patword 0x00c9 0xc0000000582c8801
patword 0x00ca 0xc0000000582c8001
patword 0x00cb 0xc0000000582c8801
patword 0x00cc 0xc0000000582c8001
patword 0x00cd 0xc0000000582c8801
patword 0x00ce 0xc0000000582c8001
patword 0x00cf 0xc0000000582c8801
patword 0x00d0 0xc0000000582c8001
patword 0x00d1 0xc0000000582c8801
patword 0x00d2 0xc0000000582c8001
patword 0x00d3 0xc0000000582c8801
patword 0x00d4 0xc0000000582c8001
patword 0x00d5 0xc0000000582c8801
patword 0x00d6 0xc0000000582c8001
patword 0x00d7 0xc0000000582c8801
patword 0x00d8 0xc0000000582c8001
patword 0x00d9 0xc0000000582c8801
patword 0x00da 0xc0000000582c8001
patword 0x00db 0x00000000582c8001
patword 0x00dc 0x00000000582c8001
patword 0x00dd 0x00000000482c8901
patword 0x00de 0x00000000482c8001
patword 0x00df 0x00000000482c8901
patword 0x00e0 0x00000000482c8001
patword 0x00e1 0x000000006b2e8001
patlimits 0x0000 0x00e1
patioctrl 0x01000000fb7fdd55
patloop 0 0x00a9 0x00da
patnloop 0 199
patwait 0 0x0018
patwaittime 0 800

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,9 @@
hostname localhost
rx_hostname localhost
udp_dstip auto
udp_srcip auto
romode analog
asamples 5000
tsamples 288

View File

@@ -0,0 +1,57 @@
from pathlib import Path
import numpy as np
from pytestqt.qt_compat import qt_api
from .utils import setup_gui, defaultParams
def test_image_acq(main, qtbot, tmp_path):
"""
tests Analog image acquisition and numpy saving
"""
params = defaultParams()
params.detector = "Moench04"
params.mode = "Analog"
params.enabled = list(range(32))
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npy'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'moench04_image_analog.npy')
assert testArray.shape == (1, 400, 400)
assert np.array_equal(dataArray, testArray)
def test_waveform_acq(main, qtbot, tmp_path):
"""
tests Analog waveform acquisition and numpy saving
"""
params = defaultParams()
params.image = False
params.detector = "Moench04"
params.mode = "Analog"
params.enabled = list(range(32))
params.plotted = params.enabled
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npz'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'moench04_waveform_adc.npz')
files = [f"ADC{i}" for i in params.enabled]
assert testArray.files == files
for i in files:
assert np.array_equal(dataArray[i], testArray[i])

View File

@@ -0,0 +1,27 @@
from pathlib import Path
from pytestqt.qt_compat import qt_api
from pyctbgui.utils.defines import Defines
from tests.gui.utils import defaultParams
def test_view_pattern(main, qtbot, tmp_path):
"""
Tests pattern file viewing
"""
params = defaultParams()
params.image = False
main.tabWidget.setCurrentIndex(Defines.pattern.tabIndex)
qtbot.keyClicks(main.patternTab.view.lineEditPatternFile, "tests/gui/data/pattern.pat")
qtbot.mouseClick(main.patternTab.view.pushButtonViewPattern, qt_api.QtCore.Qt.MouseButton.LeftButton)
qtbot.wait_until(lambda: main.patternTab.figure is not None)
assert main.patternTab.figure is not None
# save pattern
main.patternTab.figure.savefig(tmp_path / "pattern.png")
assert Path(tmp_path / "pattern.png").exists()
# pattern files generated from python3.10 libraries differ from python3.11. this would make this
# test flaky so we skip it for now
# assert filecmp.cmp("tests/gui/data/pattern.png", tmp_path / "pattern.png")

View File

@@ -0,0 +1,34 @@
import numpy as np
from pytestqt.qt_compat import qt_api
from tests.gui.utils import defaultParams, setup_gui
def test_pedestal_substraction(main, qtbot, tmp_path):
"""
tests Transceiver image acquisition, numpy saving and pedestal substraction
"""
# record 10 frames
params = defaultParams()
params.pedestalRecord = True
params.nFrames = 10
params.numpy = False
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
qtbot.wait_until(lambda: main.plotTab.view.labelPedestalFrames.text() == 'recorded frames: 10')
# apply pedestal and save
params.pedestalRecord = False
params.numpy = True
params.nFrames = 2
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npy'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
assert testArray.shape == (2, 48, 48)
assert np.array_equal(testArray, np.zeros((2, 48, 48)))

View File

@@ -0,0 +1,28 @@
# from pathlib import Path
#
# import numpy as np
# from pytestqt.qt_compat import qt_api
#
# from .utils import setup_gui, defaultParams
#
#
# def test_waveform_signals(main, qtbot, tmp_path):
# """
# tests signals waveform acquisition and numpy saving
# """
# params = defaultParams()
# params.image = False
# params.mode = "Signal"
# params.enabled = list(range(128))
# params.plotted = params.enabled
#
# setup_gui(qtbot, main, params, tmp_path=tmp_path)
#
# qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
#
# acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
# newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npz'
#
# qtbot.wait_until(lambda: newPath.is_file())
# testArray = np.load(newPath)
#

View File

@@ -0,0 +1,50 @@
from pathlib import Path
import numpy as np
from pytestqt.qt_compat import qt_api
from .utils import setup_gui, defaultParams
def test_image_acq(main, qtbot, tmp_path):
"""
tests Transceiver image acquisition and numpy saving
"""
setup_gui(qtbot, main, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npy'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'matterhorm_image_transceiver.npy')
assert testArray.shape == (1, 48, 48)
assert np.array_equal(dataArray, testArray)
def test_waveform_acq(main, qtbot, tmp_path):
"""
tests Transceiver waveform acquisition and numpy saving
"""
params = defaultParams()
params.image = False
params.enabled = [0, 1]
params.plotted = [0, 1]
setup_gui(qtbot, main, params, tmp_path=tmp_path)
qtbot.mouseClick(main.pushButtonStart, qt_api.QtCore.Qt.MouseButton.LeftButton)
acqIndex = main.acquisitionTab.view.spinBoxAcquisitionIndex.value() - 1
newPath = main.acquisitionTab.outputDir / f'{main.acquisitionTab.outputFileNamePrefix}_{acqIndex}.npz'
qtbot.wait_until(lambda: newPath.is_file())
testArray = np.load(newPath)
dataArray = np.load(Path(__file__).parent / 'data' / 'matterhorn_waveform_transceiver1and2.npz')
assert testArray.files == ['Transceiver 0', 'Transceiver 1']
assert np.array_equal(dataArray['Transceiver 0'], testArray['Transceiver 0'])
assert np.array_equal(dataArray['Transceiver 1'], testArray['Transceiver 1'])

View File

@@ -0,0 +1,78 @@
from pathlib import Path
from pyctbgui.utils.defines import Defines
class defaultParams:
image = True
detector = "Matterhorn"
numpy = True
mode = "Transceiver"
outputDir = "/tmp"
filename = "run"
nFrames = 1
enabled = []
plotted = []
pedestalRecord = True
pattern = False
def setup_gui(qtbot, widget, params=defaultParams(), tmp_path=Path('/tmp')):
if params.image:
widget.plotTab.view.radioButtonImage.setChecked(True)
widget.plotTab.view.radioButtonWaveform.setChecked(False)
if params.mode == "Transceiver":
params.enabled = [0, 1]
else:
params.enabled = range(128)
else:
widget.plotTab.view.radioButtonWaveform.setChecked(True)
widget.plotTab.view.radioButtonImage.setChecked(False)
if params.mode == "Transceiver":
widget.tabWidget.setCurrentIndex(Defines.transceiver.tabIndex)
for i in range(Defines.transceiver.count):
# check or uncheck enable/plot checkboxes
enable = getattr(widget.transceiverTab.view, f"checkBoxTransceiver{i}")
enable.setChecked(i in params.enabled)
enable = getattr(widget.transceiverTab.view, f"checkBoxTransceiver{i}Plot")
enable.setChecked(i in params.plotted)
elif params.mode == "Analog":
widget.tabWidget.setCurrentIndex(Defines.adc.tabIndex)
for i in range(Defines.adc.count):
# check or uncheck enable/plot checkboxes
enable = getattr(widget.adcTab.view, f"checkBoxADC{i}En")
enable.setChecked(i in params.enabled)
enable = getattr(widget.adcTab.view, f"checkBoxADC{i}Plot")
enable.setChecked(i in params.plotted)
qtbot.wait_until(lambda: widget.plotTab.view.radioButtonImage.isChecked() == params.image)
qtbot.keyClicks(widget.plotTab.view.comboBoxPlot, params.detector)
qtbot.wait_until(lambda: widget.plotTab.view.comboBoxPlot.currentText() == params.detector)
widget.acquisitionTab.view.checkBoxFileWriteNumpy.setChecked(params.numpy)
widget.acquisitionTab.view.comboBoxROMode.setCurrentIndex(-1)
qtbot.keyClicks(widget.acquisitionTab.view.comboBoxROMode, params.mode)
qtbot.wait_until(lambda: widget.acquisitionTab.view.comboBoxROMode.currentText() == params.mode)
widget.acquisitionTab.view.lineEditFilePath.setText(str(tmp_path))
widget.acquisitionTab.setFilePath()
widget.acquisitionTab.view.lineEditFileName.setText(params.filename)
widget.acquisitionTab.setFileName()
widget.acquisitionTab.view.spinBoxFrames.setValue(params.nFrames)
widget.acquisitionTab.setFrames()
widget.plotTab.view.radioButtonPedestalRecord.setChecked(params.pedestalRecord)
widget.plotTab.view.radioButtonPedestalApply.setChecked(not params.pedestalRecord)
qtbot.wait_until(lambda: widget.acquisitionTab.view.spinBoxFrames.value() == params.nFrames)
assert widget.acquisitionTab.view.comboBoxROMode.currentText() == params.mode
assert widget.plotTab.view.comboBoxPlot.currentText() == params.detector
assert widget.acquisitionTab.writeNumpy == params.numpy
assert widget.acquisitionTab.view.spinBoxFrames.value() == params.nFrames
assert widget.acquisitionTab.outputDir == Path(str(tmp_path))

View File

@@ -0,0 +1,129 @@
BIT0 gHG
BIT1 DGS6 1
BIT2 pulse
BIT3 DGS7 1
BIT4 clearSSR
BIT5 DGS8 1
BIT6 inSSR
BIT7 DGS9 1
BIT8 clkSSR
BIT9 clk_fb
BIT10 prechargeConnect
BIT11 clk
BIT12 clear
BIT13 shr_out_15
BIT14 bypassCDS
BIT15 Sto2
BIT16 ENprechPre
BIT17 Sto0_bot
BIT18 pulseOFF
BIT19 Sto1
BIT20 BYPASS
BIT21 connCDS
BIT22 Dsg3
BIT23 OutSSRbot
BIT24 resCDS
BIT25 res
BIT26 shr_out_31
BIT27 Dsg1
BIT28 READ
BIT29 Sto0_top
BIT30 resDGS
BIT31 shr_in
BIT48 DGS23 1
BIT49 DGS31 1
BIT50 DGS22 1
BIT51 DGS30 1
BIT52 DGS21 1
BIT53 DGS29 1
BIT54 DGS20 1
BIT55 DGS28 1
BIT56 DGS19 1
BIT57 DGS27 1
BIT58 DGS18 1
BIT59 DGS26 1
BIT60 DGS17 1
BIT61 DGS25 1
BIT62 DGS16 1
BIT63 DGS24 1
#BIT62 dbit_ena
#BIT63 adc_ena
SENSE3 T_boa.(C)
SENSE1 Va+
SENSE6 Vdd_ps
SENSE4 Vsh
SENSE2 Vcc_int
SENSE0 Vcc_iochip
SENSE7 Vcc1.8A
SENSE5 Vcc1.8D
DAC0 VprechPre
DAC1 prechargeV
DAC2 vb_sda
DAC3 vbp_colbuf
DAC4 vcasc_SFP
DAC5 ibias_SFP
DAC6 vIpreCDS
DAC7 vin_com_bot
DAC8 vIpre
DAC9 s2dVinTest
DAC10 VPH
DAC11 vIpreDGS
DAC12 vrefDGS
DAC13 empty13
DAC14 vin_com_top
DAC15 VPL
DAC16 vout_com
DAC17 empty17
ADC0 SCOL9 1
ADC1 SCOL8 1
ADC2 SCOL11 1
ADC3 SCOL10 1
ADC4 SCOL13 1
ADC5 SCOL12 1
ADC6 SCOL15 1
ADC7 SCOL14 1
ADC8 SCOL1 1
ADC9 SCOL0 1
ADC10 SCOL3 1
ADC11 SCOL2 1
ADC12 SCOL5 1
ADC13 SCOL4 1
ADC14 SCOL7 1
ADC15 SCOL6 1
ADC16 SCOL23 1
ADC17 SCOL22 1
ADC18 SCOL21 1
ADC19 SCOL20 1
ADC20 SCOL19 1
ADC21 SCOL18 1
ADC22 SCOL17 1
ADC23 SCOL16 1
ADC24 SCOL31 1
ADC25 SCOL30 1
ADC26 SCOL29 1
ADC27 SCOL28 1
ADC28 SCOL27 1
ADC29 SCOL26 1
ADC30 SCOL25 1
ADC31 SCOL24 1
VA VddA
VB VddPre
VIO VddD
#location of the pattern compiler
#PATCOMPILER /afs/psi.ch/project/sls_det_software/slsDetectorsPackage/slsDetectorSoftware/patternGenerator/generate.sh
PATCOMPILER /afs/psi.ch/project/sls_det_software/sabina/slsDetectorPackage/ctbGui/patternGenerator/generate.sh
#location of the pattern to run
#PATFILE /afs/psi.ch/user/d/dinapoli/jctb/moench02_rob/patterns_newctb/moench02_pulsing_marco.p
#PATFILE /afs/psi.ch/project/sls_det_software/sabina/moench04/patterns/moench04_readout_g4.p
#PATFILE /afs/psi.ch/user/m/maliakal_d/setupfiles/ctb_julian.pat
#PATFILE /tmp/bla.p
#PATFILE /afs/psi.ch/project/mythen/Moench04/moench04_pulsing_readout_g4.p

View File

@@ -0,0 +1,63 @@
import pytest
from pathlib import Path
from pyctbgui import alias_utility as at
def test_read_non_existing_file_throws():
with pytest.raises(FileNotFoundError):
at.read_alias_file('saijvcaiewjrvijaerijvaeoirvjveiojroiajgv')
def test_parse_sample_file():
fpath = Path(__file__).parent / 'data/moench04_start_trigger.alias'
bit_names, bit_plots, bit_colors, adc_names, adc_plots, adc_colors, dac_names, sense_names, power_names, \
pat_file_name = at.read_alias_file(fpath)
assert len(bit_names) == 64
true_names = [
'gHG', 'DGS6', 'pulse', 'DGS7', 'clearSSR', 'DGS8', 'inSSR', 'DGS9', 'clkSSR', 'clk_fb', 'prechargeConnect',
'clk', 'clear', 'shr_out_15', 'bypassCDS', 'Sto2', 'ENprechPre', 'Sto0_bot', 'pulseOFF', 'Sto1', 'BYPASS',
'connCDS', 'Dsg3', 'OutSSRbot', 'resCDS', 'res', 'shr_out_31', 'Dsg1', 'READ', 'Sto0_top', 'resDGS', 'shr_in',
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'DGS23',
'DGS31', 'DGS22', 'DGS30', 'DGS21', 'DGS29', 'DGS20', 'DGS28', 'DGS19', 'DGS27', 'DGS18', 'DGS26', 'DGS17',
'DGS25', 'DGS16', 'DGS24'
]
true_plot = [
None, True, None, True, None, True, None, True, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True, True
]
# Make sure we didn't mess up anything in this file
assert len(true_names) == len(bit_names)
for value, reference in zip(bit_names, true_names):
assert value == reference
assert len(true_plot) == 64
for value, reference in zip(bit_plots, true_plot):
assert value == reference
# sense names
true_sese = ['Vcc_iochip', 'Va+', 'Vcc_int', 'T_boa.(C)', 'Vsh', 'Vcc1.8D', 'Vdd_ps', 'Vcc1.8A']
assert len(true_sese) == 8
assert true_sese == sense_names
# ADC
true_adc = [
'SCOL9', 'SCOL8', 'SCOL11', 'SCOL10', 'SCOL13', 'SCOL12', 'SCOL15', 'SCOL14', 'SCOL1', 'SCOL0', 'SCOL3',
'SCOL2', 'SCOL5', 'SCOL4', 'SCOL7', 'SCOL6', 'SCOL23', 'SCOL22', 'SCOL21', 'SCOL20', 'SCOL19', 'SCOL18',
'SCOL17', 'SCOL16', 'SCOL31', 'SCOL30', 'SCOL29', 'SCOL28', 'SCOL27', 'SCOL26', 'SCOL25', 'SCOL24'
]
assert len(true_adc) == 32
assert true_adc == adc_names
def test_single_value_parse_gives_exception():
# Check that we get the correct exception
with pytest.raises(Exception, match=r'Alias file parsing failed'):
at.parse_alias_lines(['hej'])

View File

@@ -0,0 +1,27 @@
import numpy as np
from pyctbgui import bit_utils as bt
def test_set_bit():
num = np.int32(0)
num = bt.set_bit(num, 5)
assert num == 2**5
def test_remove_bit():
num = np.int32(2**5)
num = bt.remove_bit(num, 5)
assert num == 0
def test_manipulate_bit():
num = np.int32(0)
num = bt.manipulate_bit(True, num, 5) # True means setting bit
assert num == 2**5
def test_manipulate_bit2():
num = np.int32(2**8)
num = bt.manipulate_bit(False, num, 8) # False means clearing the bit
assert num == 0

View File

@@ -0,0 +1,42 @@
import numpy as np
import sys
from pyctbgui.utils import decoder
from pyctbgui.utils.pixelmap import moench04_analog, matterhorn_transceiver
def test_simple_decode():
pixel_map = np.zeros((2, 2), dtype=np.uint32)
pixel_map.flat = [0, 1, 2, 3]
raw_data = np.zeros(4, dtype=np.uint16)
raw_data.flat = [8, 9, 10, 11]
data = decoder.decode(raw_data, pixel_map)
assert data[0, 0] == 8
assert data[0, 1] == 9
assert data[1, 0] == 10
assert data[1, 1] == 11
# Make sure we didn't mess up the reference counts
assert sys.getrefcount(data) == 2
assert sys.getrefcount(raw_data) == 2
assert sys.getrefcount(pixel_map) == 2
def test_compare_python_and_c_decoding():
"""
Check that the python and C implementation give the same results
provides a regression test in case we change the C implementation
"""
pixel_map = moench04_analog()
raw_data = np.arange(400 * 400, dtype=np.uint16)
c_data = decoder.decode(raw_data, pixel_map)
py_data = decoder.moench04(raw_data)
assert (c_data == py_data).all()
pixel_map = matterhorn_transceiver()
raw_data = np.arange(48 * 48, dtype=np.uint16)
c_data = decoder.decode(raw_data, pixel_map)
py_data = decoder.matterhorn(raw_data)
assert (c_data == py_data).all()

View File

@@ -0,0 +1,160 @@
import filecmp
from pathlib import Path
import pytest
from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager
import numpy as np
def test_create_new_file(tmp_path):
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', (400, 400), np.int32)
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.writeOneFrame(np.ones([400, 400], dtype=np.int32))
npw.close()
arr = np.load(tmp_path / 'tmp.npy')
assert arr.dtype == np.int32
assert arr.shape == (4, 400, 400)
assert np.array_equal(arr, np.ones([4, 400, 400], dtype=np.int32))
np.save(tmp_path / 'tmp2.npy', np.ones([4, 400, 400], dtype=np.int32))
assert filecmp.cmp(tmp_path / 'tmp.npy', tmp_path / 'tmp2.npy')
def test_open_old_file(tmp_path):
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', (4000, ), np.float32)
npw.writeOneFrame(np.ones(4000, dtype=np.float32))
npw.writeOneFrame(np.ones(4000, dtype=np.float32))
npw.close()
npw2 = NumpyFileManager(tmp_path / 'tmp.npy', 'r+')
assert npw2.frameCount == 2
assert npw2.frameShape == (4000, )
assert npw2.dtype == np.float32
npw2.writeOneFrame(np.ones(4000, dtype=np.float32))
del npw2
np.save(tmp_path / 'tmp2.npy', np.ones([3, 4000], dtype=np.float32))
assert filecmp.cmp(tmp_path / 'tmp.npy', tmp_path / 'tmp2.npy')
@pytest.mark.parametrize('mode', ['w', 'x'])
def test_init_parameters2(mode, tmp_path):
# test opening files with missing parameters for write
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx', mode)
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx2', mode, frameShape=(12, 34))
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', mode, dtype=np.int64)
# opening new file with required parameters (this should work)
NumpyFileManager(tmp_path / 'abaababababa.npyx3', mode, dtype=np.int64, frameShape=(6, 6))
assert Path.is_file(tmp_path / 'abaababababa.npyx3')
def test_init_parameters(tmp_path):
with pytest.raises(TypeError):
NumpyFileManager()
# test opening file that does not exist
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx')
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx2', frameShape=(12, 34))
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.int64)
with pytest.raises(FileNotFoundError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.int64, frameShape=(6, 6))
# re-opening the same file
NumpyFileManager(tmp_path / 'abaababababa.npyx3', 'w', dtype=np.int64, frameShape=(6, 6))
NumpyFileManager(tmp_path / 'abaababababa.npyx3')
# re-opening the file with wrong parameters
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', frameShape=(6, 2))
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.int32)
with pytest.raises(AssertionError):
NumpyFileManager(tmp_path / 'abaababababa.npyx3', dtype=np.float32, frameShape=(5, 5))
# test resetting an existing file
npw = NumpyFileManager(tmp_path / 'tmp4.npy', 'w', dtype=np.float32, frameShape=(5, 5))
npw.writeOneFrame(np.ones((5, 5), dtype=np.float32))
npw.close()
assert np.load(tmp_path / 'tmp4.npy').shape == (1, 5, 5)
npw = NumpyFileManager(tmp_path / 'tmp4.npy', 'w', dtype=np.int64, frameShape=(7, 7))
npw.flush()
assert np.load(tmp_path / 'tmp4.npy').shape == (0, 7, 7)
# test adding frames with the wrong shape to an existing file
with pytest.raises(ValueError, match=r'frame shape given \(9, 4, 4\) '):
npw.writeOneFrame(np.ones((9, 4, 4)))
def test_get_item(tmp_path):
rng = np.random.default_rng(seed=42)
arr = rng.random((1000, 20, 20))
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', frameShape=(20, 20), dtype=arr.dtype)
for frame in arr:
npw.writeOneFrame(frame)
assert np.array_equal(npw[50:100], arr[50:100])
assert np.array_equal(npw[0:1], arr[0:1])
assert np.array_equal(npw[0:10000], arr)
assert np.array_equal(npw[999:1000], arr[999:1000])
assert np.array_equal(npw[999:1005], arr[999:1000])
assert np.array_equal(npw[49:300], arr[49:300])
assert np.array_equal(npw[88:88], arr[88:88])
assert np.array_equal(npw[0:0], arr[0:0])
assert np.array_equal(npw[0:77], arr[0:77])
assert np.array_equal(npw[77:0], arr[77:0])
with pytest.raises(NotImplementedError):
npw[-1:-3]
with pytest.raises(NotImplementedError):
npw[10:20:2]
with pytest.raises(NotImplementedError):
npw[-5:-87:5]
with pytest.raises(NotImplementedError):
npw[-5:-87:-5]
with pytest.raises(NotImplementedError):
npw.readFrames(-1, -4)
with pytest.raises(NotImplementedError):
npw.readFrames(0, -77)
with pytest.raises(NotImplementedError):
npw.readFrames(-5, -5)
def test_file_functions(tmp_path):
rng = np.random.default_rng(seed=42)
arr = rng.random((1000, 20, 20))
npw = NumpyFileManager(tmp_path / 'tmp.npy', 'w', frameShape=(20, 20), dtype=arr.dtype)
for frame in arr:
npw.writeOneFrame(frame)
assert np.array_equal(npw.read(10), arr[:10])
assert np.array_equal(npw.read(10), arr[10:20])
assert np.array_equal(npw.read(10), arr[20:30])
npw.readFrames(500, 600)
assert np.array_equal(npw.read(10), arr[30:40])
npw.readFrames(0, 2)
assert np.array_equal(npw.read(100), arr[40:140])
npw.writeOneFrame(arr[700])
assert np.array_equal(npw.read(5), arr[140:145])
npw.seek(900)
assert np.array_equal(npw.read(20), arr[900:920])
npw.seek(5)
npw.readFrames(500, 600)
assert np.array_equal(npw.read(10), arr[5:15])
def test_with_statement(tmp_path):
arr = np.ones((5, 5))
with NumpyFileManager(tmp_path / 'tmp.npy', 'w', (5, 5), arr.dtype) as npw:
npw.writeOneFrame(arr)
np.save(tmp_path / 'tmp2.npy', np.expand_dims(arr, 0))
assert filecmp.cmp(tmp_path / 'tmp2.npy', tmp_path / 'tmp.npy')

View File

@@ -0,0 +1,194 @@
import filecmp
from pathlib import Path
import pytest
from pyctbgui.utils.numpyWriter.npy_writer import NumpyFileManager
import numpy as np
from pyctbgui.utils.numpyWriter.npz_writer import NpzFileWriter
@pytest.mark.parametrize('compressed', [True, False])
def test_incremental_npz(compressed, tmp_path):
arr1 = np.ones((10, 5, 5))
arr2 = np.zeros((10, 5, 5), dtype=np.int32)
arr3 = np.ones((10, 5, 5), dtype=np.float32)
with NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed) as npz:
npz.writeArray('adc', arr1)
npz.writeArray('tx', arr2)
npz.writeArray('signal', arr3)
npzFile = np.load(tmp_path / 'tmp.npz')
assert sorted(npzFile.files) == sorted(('adc', 'tx', 'signal'))
assert np.array_equal(npzFile['adc'], np.ones((10, 5, 5)))
assert np.array_equal(npzFile['tx'], np.zeros((10, 5, 5), dtype=np.int32))
assert np.array_equal(npzFile['signal'], np.ones((10, 5, 5), dtype=np.float32))
if compressed:
np.savez_compressed(tmp_path / 'tmp2.npz', adc=arr1, tx=arr2, signal=arr3)
else:
np.savez(tmp_path / 'tmp2.npz', adc=arr1, tx=arr2, signal=arr3)
assert filecmp.cmp(tmp_path / 'tmp2.npz', tmp_path / 'tmp.npz')
@pytest.mark.parametrize('compressed', [True, False])
def test_zipping_npy_files(compressed, tmp_path):
data = {
'arr1': np.ones((10, 5, 5)),
'arr2': np.zeros((10, 5, 5), dtype=np.int32),
'arr3': np.ones((10, 5, 5), dtype=np.float32)
}
filePaths = [tmp_path / (file + '.npy') for file in data.keys()]
for file in data:
np.save(tmp_path / (file + '.npy'), data[file])
NpzFileWriter.zipNpyFiles(tmp_path / 'file.npz', filePaths, list(data.keys()), compressed=compressed)
npz = np.load(tmp_path / 'file.npz')
assert npz.files == list(data.keys())
for file in data:
assert np.array_equal(npz[file], data[file])
if compressed:
np.savez_compressed(tmp_path / 'numpy.npz', **data)
else:
np.savez(tmp_path / 'numpy.npz', **data)
numpyz = np.load(tmp_path / 'numpy.npz')
for file in data:
assert np.array_equal(numpyz[file], npz[file])
assert npz.files == numpyz.files
# different files :(
# for some reason numpy savez (most likely a trick with zipfile library) doesn't write the time
# of last modification
# assert filecmp.cmp(prefix / 'numpy.npz', prefix / 'file.npz')
@pytest.mark.parametrize('compressed', [True, False])
def test_npy_writer_with_zipfile_in_init(compressed, tmp_path):
npz = NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed)
rng = np.random.default_rng(42)
arr = rng.random((8000, 5, 5))
npz.writeArray('adc', arr)
with npz.file.open('adc.npy', mode='r') as outfile:
npw = NumpyFileManager(outfile)
assert np.array_equal(npw.readFrames(720, 7999), arr[720:7999])
def test_compression(tmp_path):
arr = np.zeros((1000, 5, 5), dtype=np.int32)
with NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=True) as npz:
npz.writeArray('adc', arr)
np.savez(tmp_path / 'tmp2.npz', adc=arr)
assert Path(tmp_path / 'tmp2.npz').stat().st_size > Path(tmp_path / 'tmp.npz').stat().st_size
@pytest.mark.parametrize('compressed', [True, False])
@pytest.mark.parametrize('isPath', [True, False])
@pytest.mark.parametrize('deleteOriginals', [True, False])
def test_delete_files(compressed, isPath, deleteOriginals, tmp_path):
data = {
'arr1': np.ones((10, 5, 5)),
'arr2': np.zeros((10, 5, 5), dtype=np.int32),
'arr3': np.ones((10, 5, 5), dtype=np.float32)
}
filePaths = [tmp_path / (file + '.npy') for file in data.keys()]
for file in data:
np.save(tmp_path / (file + '.npy'), data[file])
path = tmp_path / 'file.npz'
path = str(path) if isPath else path
NpzFileWriter.zipNpyFiles(path,
filePaths,
list(data.keys()),
deleteOriginals=deleteOriginals,
compressed=compressed)
if deleteOriginals:
for file in filePaths:
assert not Path.exists(file)
else:
for file in filePaths:
assert Path.exists(file)
def test_npz_read_frames(tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with NpzFileWriter(tmp_path / 'tmp.npz', 'r') as npz:
frames = npz.readFrames('adc', 5, 8)
assert np.array_equal(frames, arr1[5:8])
def test_file_modes(tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
# check reopening with mode w
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
assert npz.file.namelist() == []
# check reopening with mode x
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with pytest.raises(FileExistsError):
with NpzFileWriter(tmp_path / 'tmp.npz', 'x'):
pass
# check reopening with mode r
with NpzFileWriter(tmp_path / 'tmp.npz', 'r') as npz:
assert np.array_equal(npz.readFrames('adc', 4, 6), arr1[4:6])
with pytest.raises(ValueError, match=r'write\(\) requires mode \'w\'\, \'x\'\, or \'a\''):
npz.writeArray('adc2', arr1)
@pytest.mark.filterwarnings('ignore::UserWarning')
def test_file_mode_a(tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
# check reopening with mode a
with NpzFileWriter(tmp_path / 'tmp.npz', 'w') as npz:
npz.writeArray('adc', arr1)
with NpzFileWriter(tmp_path / 'tmp.npz', 'a') as npz:
npz.writeArray('adc2', arr1)
npz.writeArray('adc', arr1)
@pytest.mark.parametrize('compressed', [True, False])
def test_get_item(compressed, tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
arr2 = rng.random((3, 2, 2))
# check reopening with mode a
npz = NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed)
npz.writeArray('adc1', arr1)
npz.writeArray('adc2', arr2)
npz.writeArray('adc3', arr1)
assert np.array_equal(npz['adc1'].read(3), arr1[:3])
assert np.array_equal(npz['adc2'].read(1), arr2[:1])
assert np.array_equal(npz['adc2'].read(1), arr2[1:2])
assert np.array_equal(npz['adc2'].read(1), arr2[2:3])
assert np.array_equal(npz['adc1'].read(3), arr1[3:6])
assert np.array_equal(npz['adc1'].read(3), arr1[6:9])
@pytest.mark.parametrize('compressed', [True, False])
def test_namelist(compressed, tmp_path):
rng = np.random.default_rng(seed=42)
arr1 = rng.random((10, 5, 5))
arr2 = rng.random((3, 2, 2))
# check reopening with mode a
npz = NpzFileWriter(tmp_path / 'tmp.npz', 'w', compress_file=compressed)
npz.writeArray('adc1', arr1)
npz.writeArray('adc2', arr2)
npz.writeArray('adc3', arr1)
assert npz.namelist() == ['adc1', 'adc2', 'adc3']