script for release added, pyrefly checks are fixed for now

This commit is contained in:
markusro committed 2026-10-21 00:48:06 +02:00
1 parent 428af30c30
commit dda8ae7df0
6 files changed
+179 -89

No files matched your search

+13 -1
View File
@@ -22,13 +22,25 @@ jobs:
- name: Install Node.js and git - name: Install Node.js and git
run: | run: |
apt-get update apt-get update
apt-get -y install nodejs git lsb-release jq apt-get -y install nodejs git lsb-release jq devscripts
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
github-server-url: https://gitea.pkm.physik.tu-darmstadt.de github-server-url: https://gitea.pkm.physik.tu-darmstadt.de
- name: Set package version from release tag
if: startsWith(gitea.ref, 'refs/tags/v')
env:
TAG: ${{ gitea.ref_name }}
run: |
set -euo pipefail
VERSION="${TAG#v}"
if [ "$(dpkg-parsechangelog --show-field Version)" != "$VERSION" ]; then
dch --newversion "$VERSION" --distribution stable --force-distribution --noquery "Release $TAG"
fi
sed -i -E "s/^(__version__ = \")([^\"]+)(\")$/\1${VERSION}\3/" src/damaris/__init__.py
- name: Install build dependencies - name: Install build dependencies
run: bash requirements.debian run: bash requirements.debian
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 VERSION (for example: 0.30)"
}
if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then
usage
exit 0
fi
if [[ $# -ne 1 || ! $1 =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
usage >&2
exit 2
fi
version=$1
tag="v$version"
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
cd "$root"
if [[ -n $(git status --porcelain) ]]; then
echo "Release requires a clean working tree." >&2
exit 1
fi
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then
echo "Tag $tag already exists." >&2
exit 1
fi
command -v dch >/dev/null || { echo "Install devscripts to use dch." >&2; exit 1; }
command -v dpkg-parsechangelog >/dev/null || { echo "Install dpkg-dev to use dpkg-parsechangelog." >&2; exit 1; }
current_version=$(dpkg-parsechangelog --show-field Version)
if [[ $current_version == "$version" ]]; then
echo "debian/changelog already has version $version." >&2
exit 1
fi
dch --newversion "$version" --distribution stable --force-distribution
sed -i "s/^__version__ = .*/__version__ = \"$version\"/" src/damaris/__init__.py
if [[ $(dpkg-parsechangelog --show-field Version) != "$version" ]] ||
[[ $(sed -n 's/^__version__ = "\([^"]*\)"$/\1/p' src/damaris/__init__.py) != "$version" ]]; then
echo "Release version did not update consistently; inspect the changelog and package version." >&2
exit 1
fi
echo "About to commit the version bump and create tag $tag."
read -r -p "Continue? [y/N] " answer
if [[ ! $answer =~ ^[Yy]$ ]]; then
echo "Release preparation stopped; version and changelog edits were kept."
exit 1
fi
git add debian/changelog src/damaris/__init__.py
git commit -m "Release $tag"
git tag -a "$tag" -m "Release $tag"
echo "Created local release tag $tag. Push the commit and tag to start the package workflow."
echo " git push origin HEAD"
echo " git push origin $tag"
+25 -33
View File
@@ -12,13 +12,14 @@ import numpy
import sys import sys
import datetime import datetime
import tables import tables
from typing import IO from typing import IO, Any, Literal, cast
from scipy.signal import filtfilt, remez from scipy.signal import filtfilt, remez
_XArray = numpy.ndarray | list _XArray = numpy.ndarray | list
_YChannels = list[numpy.ndarray] _YChannels = list[numpy.ndarray]
_IndexList = list[tuple[int, int]] _IndexList = list[tuple[int, int]]
_Description = dict[str, str] _Description = dict[str, str]
_CompressionLibrary = Literal["blosc", "blosc2", "bzip2", "lzo", "zlib"]
############################################################################# #############################################################################
# # # #
# Name: Class ADC_Result # # Name: Class ADC_Result #
@@ -377,13 +378,14 @@ class ADC_Result(MeasurementData, Resultable, Drawable, DamarisFFT, Signalpath):
def write_to_hdf(self, hdffile: tables.File, where: str, name: str, title: str, complib: str | None = None, complevel: int | None = None) -> None: def write_to_hdf(self, hdffile: tables.File, where: str, name: str, title: str, complib: str | None = None, complevel: int | None = None) -> None:
accu_group=hdffile.create_group(where=where,name=name,title=title) accu_group=hdffile.create_group(where=where,name=name,title=title)
accu_group._v_attrs.damaris_type="ADC_Result" attrs = cast(Any, accu_group._v_attrs)
attrs.damaris_type="ADC_Result"
if self.contains_data(): if self.contains_data():
self.lock.acquire() self.lock.acquire()
try: try:
# save time stamps # save time stamps
if "job_date" in dir(self) and self.job_date is not None: if "job_date" in dir(self) and self.job_date is not None:
accu_group._v_attrs.time="%04d%02d%02d %02d:%02d:%02d.%03d"%(self.job_date.year, attrs.time="%04d%02d%02d %02d:%02d:%02d.%03d"%(self.job_date.year,
self.job_date.month, self.job_date.month,
self.job_date.day, self.job_date.day,
self.job_date.hour, self.job_date.hour,
@@ -393,15 +395,17 @@ class ADC_Result(MeasurementData, Resultable, Drawable, DamarisFFT, Signalpath):
if self.description is not None: if self.description is not None:
for (key,value) in self.description.items(): for (key,value) in self.description.items():
accu_group._v_attrs.__setattr__("description_"+key,str(value)) attrs.__setattr__("description_"+key,str(value))
accu_group._v_attrs.__setattr__("sampling_rate",self.sampling_rate) attrs.__setattr__("sampling_rate",self.sampling_rate)
# save interval information # save interval information
filter=None filter=None
if complib is not None: if complib is not None:
if complevel is None: if complevel is None:
complevel=9 complevel=9
filter=tables.Filters(complevel=complevel,complib=complib,shuffle=1) filter=tables.Filters(complevel=complevel,
complib=cast(_CompressionLibrary, complib),
shuffle=True)
index_table=hdffile.create_table(where=accu_group, index_table=hdffile.create_table(where=accu_group,
name="indices", name="indices",
@@ -414,7 +418,7 @@ class ADC_Result(MeasurementData, Resultable, Drawable, DamarisFFT, Signalpath):
expectedrows=len(self.index)) expectedrows=len(self.index))
index_table.flavor="numpy" index_table.flavor="numpy"
# save channel data # save channel data
new_row=index_table.row new_row = cast(Any, index_table.row)
for i in range(len(self.index)): for i in range(len(self.index)):
new_row["start"]=self.index[i][0] new_row["start"]=self.index[i][0]
new_row["dwelltime"]=1.0/self.sampling_rate new_row["dwelltime"]=1.0/self.sampling_rate
@@ -436,27 +440,14 @@ class ADC_Result(MeasurementData, Resultable, Drawable, DamarisFFT, Signalpath):
# save data # save data
time_slice_data=None time_slice_data=None
if filter is not None: if filter is not None:
chunkshape = numpy.shape(timedata) chunkshape = (min(timedata.shape[0], 1024 * 8), timedata.shape[1])
if len(chunkshape) <= 1: time_slice_data=hdffile.create_carray(accu_group,
chunkshape = (min(chunkshape[0],1024*8),) name="adc_data",
else: shape=timedata.shape,
chunkshape = (min(chunkshape[0],1024*8), chunkshape[1]) chunkshape=chunkshape,
if tables.__version__[0]=="1": atom=tables.Int16Atom(),
time_slice_data=hdffile.create_carray(accu_group, filters=filter,
name="adc_data", title="adc data")
shape=timedata.shape,
atom=tables.Int16Atom(shape=chunkshape,
flavor="numpy"),
filters=filter,
title="adc data")
else:
time_slice_data=hdffile.create_carray(accu_group,
name="adc_data",
shape=timedata.shape,
chunkshape=chunkshape,
atom=tables.Int16Atom(),
filters=filter,
title="adc data")
time_slice_data[:]=timedata time_slice_data[:]=timedata
else: else:
time_slice_data=hdffile.create_array(accu_group, time_slice_data=hdffile.create_array(accu_group,
@@ -684,7 +675,8 @@ def read_from_hdf(hdf_node: object) -> ADC_Result | None:
if not isinstance(hdf_node, tables.Group): if not isinstance(hdf_node, tables.Group):
return None return None
if hdf_node._v_attrs.damaris_type!="ADC_Result": attrs = cast(Any, hdf_node._v_attrs)
if attrs.damaris_type!="ADC_Result":
return None return None
if not (hdf_node.__contains__("indices") and hdf_node.__contains__("adc_data")): if not (hdf_node.__contains__("indices") and hdf_node.__contains__("adc_data")):
@@ -696,12 +688,12 @@ def read_from_hdf(hdf_node: object) -> ADC_Result | None:
adc.set_title(hdf_node._v_title) adc.set_title(hdf_node._v_title)
# populate description dictionary # populate description dictionary
adc.description={} adc.description={}
for attrname in hdf_node._v_attrs._v_attrnamesuser: for attrname in attrs._v_attrnamesuser:
if attrname.startswith("description_"): if attrname.startswith("description_"):
adc.description[attrname[12:]]=hdf_node._v_attrs.__getattr__(attrname) adc.description[attrname[12:]]=attrs.__getattr__(attrname)
if "time" in dir(hdf_node._v_attrs): if "time" in dir(attrs):
timestring=hdf_node._v_attrs.__getattr__("time") timestring=attrs.__getattr__("time")
adc.job_date=datetime.datetime(int(timestring[:4]), # year adc.job_date=datetime.datetime(int(timestring[:4]), # year
int(timestring[4:6]), # month int(timestring[4:6]), # month
int(timestring[6:8]), # day int(timestring[6:8]), # day
+47 -47
View File
@@ -26,12 +26,13 @@ import datetime # added by Oleg Petrov
import ctypes # added by Oleg Petrov import ctypes # added by Oleg Petrov
import struct # added by Oleg Petrov import struct # added by Oleg Petrov
import os # added by Oleg Petrov import os # added by Oleg Petrov
from typing import IO from typing import IO, Any, Literal, cast
_XArray = numpy.ndarray | list _XArray = numpy.ndarray | list
_YChannels = list[numpy.ndarray] _YChannels = list[numpy.ndarray]
_IndexList = list[tuple[int, int]] _IndexList = list[tuple[int, int]]
_Description = dict[str, str] _Description = dict[str, str]
_CompressionLibrary = Literal["blosc", "blosc2", "bzip2", "lzo", "zlib"]
class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath): class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath):
@@ -307,7 +308,7 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
for i in range(len(xdata)): for i in range(len(xdata)):
dest.write("%e"%xdata[i]) dest.write("%e"%xdata[i])
for j in range(ch_no): for j in range(ch_no):
if self.use_error: if self.use_error and yerr is not None:
dest.write("%s%e%s%e"%(delimiter, ydata[j][i], delimiter, yerr[j][i])) dest.write("%s%e%s%e"%(delimiter, ydata[j][i], delimiter, yerr[j][i]))
else: else:
dest.write("%s%e"%(delimiter,ydata[j][i])) dest.write("%s%e"%(delimiter,ydata[j][i]))
@@ -358,7 +359,7 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
self.lock.release() self.lock.release()
# ------------- added by Oleg Petrov, 10 Sep 2013 ----------------------- # ------------- added by Oleg Petrov, 10 Sep 2013 -----------------------
def write_to_tecmag(self, destination = sys.stdout, nrecords: int = 1,\ def write_to_tecmag(self, destination: str | IO[bytes] = sys.stdout.buffer, nrecords: int = 1,\
frequency: float = 100.,\ frequency: float = 100.,\
last_delay: float = 1.,\ last_delay: float = 1.,\
receiver_phase: float = 0.,\ receiver_phase: float = 0.,\
@@ -388,8 +389,8 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
else: else:
record = (self.job_id/self.n)%nrecords + 1 record = (self.job_id/self.n)%nrecords + 1
the_destination=destination the_destination: IO[bytes] | None = None
if type(destination) in (str,): if isinstance(destination, str):
if record == 1 and os.path.exists(destination): if record == 1 and os.path.exists(destination):
os.rename(destination, os.path.dirname(destination)+'/~'+os.path.basename(destination)) os.rename(destination, os.path.dirname(destination)+'/~'+os.path.basename(destination))
@@ -420,7 +421,10 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
data = data.flatten() data = data.flatten()
if record == 1: if record == 1:
the_destination=open(destination, "wb") if isinstance(destination, str):
the_destination = open(destination, "wb")
else:
the_destination = destination
# allocate space for all records in advance: # allocate space for all records in advance:
buff = ctypes.create_string_buffer(1056+data_offset+2068) buff = ctypes.create_string_buffer(1056+data_offset+2068)
@@ -481,20 +485,24 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
struct.pack_into('4s', buff, 1056+data_offset+2060, 'PSEQ') # 'PSEQ' tag 658476 struct.pack_into('4s', buff, 1056+data_offset+2060, 'PSEQ') # 'PSEQ' tag 658476
struct.pack_into('?', buff, 1056+data_offset+2064, False) # BOOLean 658480 struct.pack_into('?', buff, 1056+data_offset+2064, False) # BOOLean 658480
the_destination.write(buff) the_destination.write(buff.raw)
else: else:
the_destination=open(destination, "rb+") if isinstance(destination, str):
the_destination = open(destination, "rb+")
else:
the_destination = destination
buff = ctypes.create_string_buffer(4*2*npts[0]) buff = ctypes.create_string_buffer(4*2*npts[0])
struct.pack_into('%sf' % (2*npts[0]), buff, 0, *data) struct.pack_into('%sf' % (2*npts[0]), buff, 0, *data)
the_destination.seek(1056+4*2*npts[0]*(record-1)) the_destination.seek(1056+4*2*npts[0]*(record-1))
the_destination.write(buff) the_destination.write(buff.raw)
the_destination = None
ydata=None ydata=None
finally: finally:
if isinstance(destination, str) and the_destination is not None:
the_destination.close()
self.lock.release() self.lock.release()
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@@ -518,25 +526,28 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
:param complevel: compression level. :param complevel: compression level.
""" """
accu_group=hdffile.create_group(where=where,name=name,title=title) accu_group=hdffile.create_group(where=where,name=name,title=title)
accu_group._v_attrs.damaris_type="Accumulation" attrs = cast(Any, accu_group._v_attrs)
attrs.damaris_type="Accumulation"
if self.contains_data(): if self.contains_data():
self.lock.acquire() self.lock.acquire()
try: try:
# save time stamps # save time stamps
if self.time_period is not None and len(self.time_period)>0: if self.time_period is not None and len(self.time_period)>0:
accu_group._v_attrs.earliest_time = self.time_period[0].isoformat(sep=' ', timespec='milliseconds') attrs.earliest_time = self.time_period[0].isoformat(sep=' ', timespec='milliseconds')
accu_group._v_attrs.oldest_time = self.time_period[1].isoformat(sep=' ', timespec='milliseconds') attrs.oldest_time = self.time_period[1].isoformat(sep=' ', timespec='milliseconds')
if self.common_descriptions is not None: if self.common_descriptions is not None:
for (key,value) in self.common_descriptions.items(): for (key,value) in self.common_descriptions.items():
accu_group._v_attrs.__setattr__("description_"+key,str(value)) attrs.__setattr__("description_"+key,str(value))
accu_group._v_attrs.__setattr__("sampling_rate",self.sampling_rate) attrs.__setattr__("sampling_rate",self.sampling_rate)
filter=None filter=None
if complib is not None: if complib is not None:
if complevel is None: if complevel is None:
complevel=3 complevel=3
filter=tables.Filters(complevel=complevel,complib=complib,shuffle=1) filter=tables.Filters(complevel=complevel,
complib=cast(_CompressionLibrary, complib),
shuffle=True)
# save interval information # save interval information
# start save index_table # start save index_table
@@ -553,7 +564,7 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
expectedrows=len(self.index)) expectedrows=len(self.index))
index_table.flavor="numpy" index_table.flavor="numpy"
# save interval data # save interval data
new_row=index_table.row new_row = cast(Any, index_table.row)
for i in range(len(self.index)): for i in range(len(self.index)):
new_row["start"]=self.index[i][0] new_row["start"]=self.index[i][0]
new_row["dwelltime"]=1.0/self.sampling_rate new_row["dwelltime"]=1.0/self.sampling_rate
@@ -574,7 +585,7 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
title="job_ids used for accumulation", title="job_ids used for accumulation",
filters=filter, filters=filter,
expectedrows=len(self.job_ids)) expectedrows=len(self.job_ids))
new_row=jobid_table.row new_row = cast(Any, jobid_table.row)
for i,job_id in enumerate(self.job_ids): for i,job_id in enumerate(self.job_ids):
new_row["job_date"] = self.job_ids[job_id].isoformat(timespec='milliseconds') new_row["job_date"] = self.job_ids[job_id].isoformat(timespec='milliseconds')
new_row["job_id"]=job_id new_row["job_id"]=job_id
@@ -595,27 +606,14 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
# save data # save data
time_slice_data=None time_slice_data=None
if filter is not None: if filter is not None:
chunkshape=timedata.shape chunkshape = (min(timedata.shape[0], 1024 * 8), timedata.shape[1])
if len(chunkshape) <= 1: time_slice_data=hdffile.create_carray(accu_group,
chunkshape = (min(chunkshape[0],1024*8),) name="accu_data",
else: shape=timedata.shape,
chunkshape = (min(chunkshape[0],1024*8), chunkshape[1]) chunkshape=chunkshape,
if tables.__version__[0]=="1": atom=tables.Float32Atom(),
time_slice_data=hdffile.create_carray(accu_group, filters=filter,
name="accu_data", title="accu data")
shape=timedata.shape,
atom=tables.Float32Atom(shape=chunkshape,
flavor="numpy"),
filters=filter,
title="accu data")
else:
time_slice_data=hdffile.create_carray(accu_group,
name="accu_data",
shape=timedata.shape,
chunkshape=chunkshape,
atom=tables.Float32Atom(),
filters=filter,
title="accu data")
time_slice_data[:]=timedata time_slice_data[:]=timedata
else: else:
@@ -1111,7 +1109,8 @@ class Accumulation(MeasurementData, Errorable, Drawable, DamarisFFT, Signalpath)
self.set_title(self.__title_pattern % self.n) self.set_title(self.__title_pattern % self.n)
if hasattr(other, "is_clipped"): if hasattr(other, "is_clipped"):
self.is_clipped = other.is_clipped self.is_clipped = other.is_clipped
self.common_descriptions=other.common_descriptions.copy() self.common_descriptions = (other.common_descriptions.copy()
if other.common_descriptions is not None else None)
self.time_period=other.time_period[:] if other.time_period is not None else None self.time_period=other.time_period[:] if other.time_period is not None else None
self.job_id = other.job_id # added by Oleg Petrov self.job_id = other.job_id # added by Oleg Petrov
self.job_ids.update(other.job_ids) self.job_ids.update(other.job_ids)
@@ -1213,7 +1212,8 @@ def read_from_hdf(hdf_node: object) -> "Accumulation | None":
if not isinstance(hdf_node, tables.Group): if not isinstance(hdf_node, tables.Group):
return None return None
if hdf_node._v_attrs.damaris_type!="Accumulation": attrs = cast(Any, hdf_node._v_attrs)
if attrs.damaris_type!="Accumulation":
return None return None
if not (hdf_node.__contains__("indices") and hdf_node.__contains__("accu_data")): if not (hdf_node.__contains__("indices") and hdf_node.__contains__("accu_data")):
@@ -1224,13 +1224,13 @@ def read_from_hdf(hdf_node: object) -> "Accumulation | None":
# populate description dictionary # populate description dictionary
accu.common_descriptions={} accu.common_descriptions={}
for attrname in hdf_node._v_attrs._v_attrnamesuser: for attrname in attrs._v_attrnamesuser:
if attrname.startswith("description_"): if attrname.startswith("description_"):
accu.common_descriptions[attrname[12:]]=hdf_node._v_attrs.__getattr__(attrname) accu.common_descriptions[attrname[12:]]=attrs.__getattr__(attrname)
earliest_time=None earliest_time=None
if "earliest_time" in dir(hdf_node._v_attrs): if "earliest_time" in dir(attrs):
timestring=hdf_node._v_attrs.__getattr__("earliest_time") timestring=attrs.__getattr__("earliest_time")
# Handle both formats: "20260705 19:13:59.162" and "2026-07-05 19:13:59.162" # Handle both formats: "20260705 19:13:59.162" and "2026-07-05 19:13:59.162"
if '-' in timestring: if '-' in timestring:
# New format: "2026-07-05 19:13:59.162" # New format: "2026-07-05 19:13:59.162"
@@ -1261,8 +1261,8 @@ def read_from_hdf(hdf_node: object) -> "Accumulation | None":
) )
oldest_time=None oldest_time=None
if "oldest_time" in dir(hdf_node._v_attrs): if "oldest_time" in dir(attrs):
timestring=hdf_node._v_attrs.__getattr__("oldest_time") timestring=attrs.__getattr__("oldest_time")
# Handle both formats: "20260705 19:13:59.162" and "2026-07-05 19:13:59.162" # Handle both formats: "20260705 19:13:59.162" and "2026-07-05 19:13:59.162"
if '-' in timestring: if '-' in timestring:
# New format: "2026-07-05 19:13:59.162" # New format: "2026-07-05 19:13:59.162"
+15 -8
View File
@@ -4,7 +4,7 @@ import sys
import tables import tables
import numpy import numpy
import collections import collections
from typing import IO from typing import IO, Any, Literal, cast
from . import Drawable from . import Drawable
## provide gaussian statistics for a series of measured data points ## provide gaussian statistics for a series of measured data points
@@ -31,7 +31,10 @@ class AccumulatedValue:
self.y2=self.y**2 self.y2=self.y**2
self.n=1 self.n=1
elif mean_err is None: elif mean_err is None:
self.n=max(1, int(n)) if n is None:
self.n=1
else:
self.n=max(1, n)
self.y=float(mean)*self.n self.y=float(mean)*self.n
self.y2=(float(mean)**2)*self.n self.y2=(float(mean)**2)*self.n
elif n is None: elif n is None:
@@ -240,7 +243,9 @@ class MeasurementResult(Drawable.Drawable, collections.UserDict):
if complib is not None: if complib is not None:
if complevel is None: if complevel is None:
complevel=9 complevel=9
filter=tables.Filters(complevel=complevel,complib=complib,shuffle=1) filter=tables.Filters(complevel=complevel,
complib=cast(Literal["blosc", "blosc2", "bzip2", "lzo", "zlib"], complib),
shuffle=True)
mr_table=hdffile.create_table(where=where,name=name, mr_table=hdffile.create_table(where=where,name=name,
description=h5_table_format, description=h5_table_format,
@@ -248,11 +253,12 @@ class MeasurementResult(Drawable.Drawable, collections.UserDict):
filters=filter, filters=filter,
expectedrows=len(self)) expectedrows=len(self))
mr_table.flavor="numpy" mr_table.flavor="numpy"
mr_table.attrs.damaris_type="MeasurementResult" attrs = cast(Any, mr_table.attrs)
attrs.damaris_type="MeasurementResult"
self.lock.acquire() self.lock.acquire()
try: try:
mr_table.attrs.quantity_name=self.quantity_name attrs.quantity_name=self.quantity_name
row=mr_table.row row = cast(Any, mr_table.row)
xdata=self.get_xdata() xdata=self.get_xdata()
if xdata.shape[0]!=0: if xdata.shape[0]!=0:
for x in xdata: for x in xdata:
@@ -276,10 +282,11 @@ def read_from_hdf(hdf_node: object) -> "MeasurementResult | None":
if not isinstance(hdf_node, tables.Table): if not isinstance(hdf_node, tables.Table):
return None return None
if hdf_node._v_attrs.damaris_type!="MeasurementResult": attrs = cast(Any, hdf_node._v_attrs)
if attrs.damaris_type!="MeasurementResult":
return None return None
mr=MeasurementResult(hdf_node._v_attrs.quantity_name) mr=MeasurementResult(attrs.quantity_name)
for r in hdf_node.iterrows(): for r in hdf_node.iterrows():
mr[r["x"]]=AccumulatedValue(r["y"],r["y_err"],r["n"]) mr[r["x"]]=AccumulatedValue(r["y"],r["y_err"],r["n"])
+14
View File
@@ -360,6 +360,20 @@ class TestAccumulation(unittest.TestCase):
r *= 2 r *= 2
np.testing.assert_array_equal(accu.y[0], np.array([10, 20, 30], dtype="float32")) np.testing.assert_array_equal(accu.y[0], np.array([10, 20, 30], dtype="float32"))
def test_empty_iadd_accumulation_without_common_descriptions(self):
"""An accumulation without common descriptions can be copied in-place."""
other = Accumulation(x=np.array([0.0, 1.0]),
y=[np.array([10.0, 20.0])],
n=1,
index=[(0, 1)],
sampl_freq=1000.0)
accu = Accumulation()
accu += other
self.assertIsNone(accu.common_descriptions)
np.testing.assert_array_equal(accu.y[0], other.y[0])
def test_accumulation_plus_accumulation_keeps_both_job_ids(self): def test_accumulation_plus_accumulation_keeps_both_job_ids(self):
"""accu1 + accu2 must keep the provenance of both operands.""" """accu1 + accu2 must keep the provenance of both operands."""
adc1 = self.create_adc_result() adc1 = self.create_adc_result()