Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-npTDMS for openSUSE:Factory checked in at 2026-03-30 18:30:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-npTDMS (Old) and /work/SRC/openSUSE:Factory/.python-npTDMS.new.1999 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-npTDMS" Mon Mar 30 18:30:52 2026 rev:7 rq:1343491 version:1.10.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-npTDMS/python-npTDMS.changes 2025-05-09 18:52:50.944799890 +0200 +++ /work/SRC/openSUSE:Factory/.python-npTDMS.new.1999/python-npTDMS.changes 2026-03-30 18:33:52.433516416 +0200 @@ -1,0 +2,9 @@ +Sun Mar 29 17:43:46 UTC 2026 - Dirk Müller <[email protected]> + +- update to 1.10.0: + * Fix tests for numpy 2 + * Update supported Python versions + * Fix overflow when computing seek position + * Drastic performance improvements for reads + +------------------------------------------------------------------- Old: ---- npTDMS-1.9.0.tar.gz New: ---- npTDMS-1.10.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-npTDMS.spec ++++++ --- /var/tmp/diff_new_pack.JfyyVh/_old 2026-03-30 18:33:53.101544345 +0200 +++ /var/tmp/diff_new_pack.JfyyVh/_new 2026-03-30 18:33:53.105544512 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-npTDMS # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: python-npTDMS -Version: 1.9.0 +Version: 1.10.0 Release: 0 Summary: Python module for reading TDMS files produced by LabView License: LGPL-3.0-only @@ -37,6 +37,7 @@ BuildRequires: %{python_module hypothesis} BuildRequires: %{python_module pytest-benchmark} BuildRequires: %{python_module pytest} +BuildRequires: %{python_module scipy} # /SECTION %python_subpackages ++++++ npTDMS-1.9.0.tar.gz -> npTDMS-1.10.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/.github/workflows/ci-cd.yml new/npTDMS-1.10.0/.github/workflows/ci-cd.yml --- old/npTDMS-1.9.0/.github/workflows/ci-cd.yml 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/.github/workflows/ci-cd.yml 2025-01-22 02:30:41.000000000 +0100 @@ -15,7 +15,7 @@ - name: Setup Python uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.12' - name: Install tox run: pip install tox - name: Run pycodestyle @@ -29,7 +29,7 @@ strategy: fail-fast: false matrix: - python: ['3.8', '3.9', '3.10', '3.11'] + python: ['3.9', '3.10', '3.11', '3.12'] os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -69,9 +69,11 @@ - name: Setup Python uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.12' - name: Create package - run: python setup.py sdist + run: | + python -m pip install setuptools + python setup.py sdist - name: Publish package uses: pypa/gh-action-pypi-publish@release/v1 with: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/.gitignore new/npTDMS-1.10.0/.gitignore --- old/npTDMS-1.9.0/.gitignore 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/.gitignore 2025-01-22 02:30:41.000000000 +0100 @@ -13,6 +13,7 @@ .ipynb_checkpoints .vscode *.ipynb +.idea # Wercker directories _builds diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/nptdms/export/hdf_export.py new/npTDMS-1.10.0/nptdms/export/hdf_export.py --- old/npTDMS-1.9.0/nptdms/export/hdf_export.py 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/nptdms/export/hdf_export.py 2025-01-22 02:30:41.000000000 +0100 @@ -92,5 +92,5 @@ """ Convert a value into a format suitable for an HDF attribute """ if isinstance(value, np.datetime64): - return np.string_(np.datetime_as_string(value, unit='us', timezone='UTC')) + return np.bytes_(np.datetime_as_string(value, unit='us', timezone='UTC')) return value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/nptdms/tdms_segment.py new/npTDMS-1.10.0/nptdms/tdms_segment.py --- old/npTDMS-1.9.0/nptdms/tdms_segment.py 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/nptdms/tdms_segment.py 2025-01-22 02:30:41.000000000 +0100 @@ -45,6 +45,9 @@ 'final_chunk_lengths_override', 'object_index', 'segment_incomplete', + 'has_daqmx_objects_cached', + 'chunk_size_cached', + 'data_objects_cached', ] def __init__(self, position, toc_mask, next_segment_pos, data_position, segment_incomplete): @@ -57,6 +60,9 @@ self.ordered_objects = None self.object_index = None self.segment_incomplete = segment_incomplete + self.has_daqmx_objects_cached = None + self.chunk_size_cached = None + self.data_objects_cached = None def __repr__(self): return "<TdmsSegment at position %d>" % self.position @@ -135,6 +141,7 @@ if index_cache is not None: self.object_index = index_cache.get_index(self.ordered_objects) + self._calculate_chunks() return properties @@ -261,13 +268,18 @@ f.seek(self.data_position) - data_objects = [o for o in self.ordered_objects if o.has_data] chunk_size = self._get_chunk_size() + # Ensure we're working with Python ints as np.int32 values could overflow + # (https://github.com/adamreeve/npTDMS/issues/338) + chunk_offset = int(chunk_offset) + if chunk_offset > 0: f.seek(chunk_size * chunk_offset, os.SEEK_CUR) stop_chunk = self.num_chunks if num_chunks is None else num_chunks + chunk_offset - for chunk in self._read_channel_data_chunks(f, data_objects, channel_path, chunk_offset, stop_chunk): + for chunk in self._read_channel_data_chunks( + f, self._get_data_objects(), channel_path, chunk_offset, stop_chunk, chunk_size + ): yield chunk def _calculate_chunks(self): @@ -346,11 +358,15 @@ return TdmsSegmentObject(object_path) def _get_chunk_size(self): + if self.chunk_size_cached is not None: + return self.chunk_size_cached + if self._have_daqmx_objects(): - return get_daqmx_chunk_size(self.ordered_objects) - return sum( - o.data_size - for o in self.ordered_objects if o.has_data) + self.chunk_size_cached = int(get_daqmx_chunk_size(self.ordered_objects)) + return self.chunk_size_cached + + self.chunk_size_cached = int(sum(o.data_size for o in self.ordered_objects if o.has_data)) + return self.chunk_size_cached def _read_data_chunks(self, file, data_objects, num_chunks): """ Read multiple data chunks at once @@ -360,13 +376,17 @@ for chunk in reader.read_data_chunks(file, data_objects, num_chunks): yield chunk - def _read_channel_data_chunks(self, file, data_objects, channel_path, chunk_offset, stop_chunk): + def _read_channel_data_chunks(self, file, data_objects, channel_path, chunk_offset, stop_chunk, chunk_size): """ Read multiple data chunks for a single channel at once In the base case we read each chunk individually but subclasses can override this """ reader = self._get_data_reader() - for chunk in reader.read_channel_data_chunks(file, data_objects, channel_path, chunk_offset, stop_chunk): + initial_position = file.tell() + for i, chunk in enumerate(reader.read_channel_data_chunks( + file, data_objects, channel_path, chunk_offset, stop_chunk + )): yield chunk + file.seek(initial_position + (i + 1) * chunk_size) def _get_data_reader(self): endianness = '>' if (self.toc_mask & toc_properties['kTocBigEndian']) else '<' @@ -378,6 +398,9 @@ return ContiguousDataReader(self.num_chunks, self.final_chunk_lengths_override, endianness) def _have_daqmx_objects(self): + if self.has_daqmx_objects_cached is not None: + return self.has_daqmx_objects_cached + data_obj_count = 0 daqmx_count = 0 for o in self.ordered_objects: @@ -386,12 +409,12 @@ if isinstance(o, DaqmxSegmentObject): daqmx_count += 1 if daqmx_count == 0: - return False - if daqmx_count == data_obj_count: - return True - if daqmx_count > 0: + self.has_daqmx_objects_cached = False + elif daqmx_count == data_obj_count: + self.has_daqmx_objects_cached = True + elif daqmx_count > 0: raise Exception("Cannot read mixed DAQmx and non-DAQmx data") - return False + return self.has_daqmx_objects_cached def _have_interleaved_data(self): """ Whether data in this segment is interleaved. Assumes data is not DAQmx. @@ -415,6 +438,13 @@ else: raise ValueError("Cannot read interleaved segment containing channels with unsized types") + def _get_data_objects(self): + if self.data_objects_cached is not None: + return self.data_objects_cached + + self.data_objects_cached = [o for o in self.ordered_objects if o.has_data] + return self.data_objects_cached + class InterleavedDataReader(BaseDataReader): """ Reads data in a TDMS segment with interleaved data @@ -487,24 +517,27 @@ """ Read data from a chunk for a single channel """ channel_data = RawChannelDataChunk.empty() + current_position = file.tell() for obj in data_objects: number_values = self._get_channel_number_values(obj, chunk_index) if obj.path == channel_path: + file.seek(current_position) channel_data = RawChannelDataChunk.channel_data(obj.read_values(file, number_values, self.endianness)) + current_position = file.tell() + break elif number_values == obj.number_values: # Seek over data for other channel data - file.seek(obj.data_size, os.SEEK_CUR) - else: + current_position += obj.data_size + elif obj.data_type.size is not None: # In last chunk with reduced chunk size - if obj.data_type.size is None: - # Type is unsized (eg. string), try reading number of values - obj.read_values(file, number_values, self.endianness) - else: - file.seek(obj.data_type.size * number_values, os.SEEK_CUR) + current_position += obj.data_type.size * number_values + else: + raise Exception("Cannot skip over channel with unsized type in a truncated segment") + return channel_data def _get_channel_number_values(self, obj, chunk_index): - if chunk_index == (self.num_chunks - 1) and self.final_chunk_lengths_override is not None: + if self.final_chunk_lengths_override is not None and chunk_index == (self.num_chunks - 1): return self.final_chunk_lengths_override.get(obj.path, 0) else: return obj.number_values diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/nptdms/test/test_thermocouples.py new/npTDMS-1.10.0/nptdms/test/test_thermocouples.py --- old/npTDMS-1.9.0/nptdms/test/test_thermocouples.py 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/nptdms/test/test_thermocouples.py 2025-01-22 02:30:41.000000000 +0100 @@ -193,3 +193,21 @@ reference_temperature = reference_thermocouple.inverse_CmV(voltage, Tref=0.0) temperature = thermocouple.mv_to_celsius(voltage) assert abs(temperature - reference_temperature) < max_error + 1.0E-6 + + [email protected](autouse=True) +def patch_thermocouples_reference(monkeypatch): + """ + thermocouples_reference creates an array with np.array(T, copy=False) + which causes an error on numpy 2 for non-array inputs. + We can't workaround this by only passing in numpy arrays as there are also + internal uses that cause this error, so monkeypatch to fix this. + """ + prev_call = thermocouples_reference.function_types.Polynomial_Gaussian_Piecewise_Function.__call__ + + def new_call(self, t, *args, **kwargs): + t = np.asarray(t) + return prev_call(self, t, *args, **kwargs) + + monkeypatch.setattr( + thermocouples_reference.function_types.Polynomial_Gaussian_Piecewise_Function, "__call__", new_call) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/setup.cfg new/npTDMS-1.10.0/setup.cfg --- old/npTDMS-1.9.0/setup.cfg 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/setup.cfg 2025-01-22 02:30:41.000000000 +0100 @@ -1,6 +1,6 @@ [metadata] name = npTDMS -version = 1.9.0 +version = 1.10.0 description = Cross-platform, NumPy based module for reading TDMS files produced by LabView author = Adam Reeve author_email = [email protected] @@ -12,10 +12,10 @@ Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 Topic :: Scientific/Engineering License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) Intended Audience :: Science/Research diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/npTDMS-1.9.0/tox.ini new/npTDMS-1.10.0/tox.ini --- old/npTDMS-1.9.0/tox.ini 2024-03-20 23:37:21.000000000 +0100 +++ new/npTDMS-1.10.0/tox.ini 2025-01-22 02:30:41.000000000 +0100 @@ -1,5 +1,5 @@ [tox] -envlist = py{37,38,39,310},pycodestyle +envlist = py{39,310,311,312},pycodestyle [pycodestyle] max-line-length = 120
