Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-gwpy for openSUSE:Factory checked in at 2024-09-16 17:43:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-gwpy (Old) and /work/SRC/openSUSE:Factory/.python-gwpy.new.29891 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-gwpy" Mon Sep 16 17:43:21 2024 rev:6 rq:1201361 version:3.0.9 Changes: -------- --- /work/SRC/openSUSE:Factory/python-gwpy/python-gwpy.changes 2024-01-18 21:55:02.968348409 +0100 +++ /work/SRC/openSUSE:Factory/.python-gwpy.new.29891/python-gwpy.changes 2024-09-16 17:44:30.700619033 +0200 @@ -1,0 +2,22 @@ +Sun Sep 15 22:37:05 UTC 2024 - Atri Bhattacharya <badshah...@gmail.com> + +- Update to version 3.0.9: + * [gh#gwpy/gwpy#1616] Support parsing multiple FFL files for a + single dataset + * [gh#gwpy/gwpy#1637] Remove redundant usetex test function + * [gh#gwpy/gwpy#1641] Add tests for gwpy.timeseries.io.cache + * [gh#gwpy/gwpy#1747] Fix argument reuse bug in gwpy.cli + * [gh#gwpy/gwpy#1749] Add Virgo 'HoftOnline' as a preferred + frametype + * [gh#gwpy/gwpy#1753] Fix usage of Hann window for Scipy 1.13.0 + * [gh#gwpy/gwpy#1755] Fix test failure with Zenodo rate limit + * [gh#gwpy/gwpy#1760] Fix array copy compatibility with numpy 2 + * [gh#gwpy/gwpy#1762] Fix usage of Scipy firwin + * [gh#gwpy/gwpy#1763] Fix usage of Scipy trapezoid in gwpy.astro + * [gh#gwpy/gwpy#1764] Improve error handling when reading GWF + with LALFrame + * [gh#gwpy/gwpy#1765] Add extra unit alias for 's' +- Add gwpy-numpy-2.0-types.patch for compatibility with numpy 2.0 + float types <https://gitlab.com/gwpy/gwpy/-/merge_requests/1782> + +------------------------------------------------------------------- Old: ---- gwpy-3.0.8.tar.gz New: ---- gwpy-3.0.9.tar.gz gwpy-numpy-2.0-types.patch BETA DEBUG BEGIN: New: * [gh#gwpy/gwpy#1765] Add extra unit alias for 's' - Add gwpy-numpy-2.0-types.patch for compatibility with numpy 2.0 float types <https://gitlab.com/gwpy/gwpy/-/merge_requests/1782> BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-gwpy.spec ++++++ --- /var/tmp/diff_new_pack.WgNZXu/_old 2024-09-16 17:44:31.396647818 +0200 +++ /var/tmp/diff_new_pack.WgNZXu/_new 2024-09-16 17:44:31.396647818 +0200 @@ -17,12 +17,14 @@ Name: python-gwpy -Version: 3.0.8 +Version: 3.0.9 Release: 0 Summary: A python package for gravitational-wave astrophysics License: GPL-3.0-only URL: https://gwpy.github.io/ Source: https://files.pythonhosted.org/packages/source/g/gwpy/gwpy-%{version}.tar.gz +# PATCH-FIX-UPSTREAM https://gitlab.com/gwpy/gwpy/-/merge_requests/1782 +Patch0: gwpy-numpy-2.0-types.patch BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module pip} BuildRequires: %{python_module setuptools_scm} @@ -78,7 +80,7 @@ # Unsupported archs by upstream ExcludeArch: %{ix86} Requires(post): update-alternatives -Requires(postun):update-alternatives +Requires(postun): update-alternatives %python_subpackages %description ++++++ gwpy-3.0.8.tar.gz -> gwpy-3.0.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/PKG-INFO new/gwpy-3.0.9/PKG-INFO --- old/gwpy-3.0.8/PKG-INFO 2024-01-12 11:46:18.256800200 +0100 +++ new/gwpy-3.0.9/PKG-INFO 2024-07-12 18:24:35.865938000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: gwpy -Version: 3.0.8 +Version: 3.0.9 Summary: A python package for gravitational-wave astrophysics Author-email: Duncan Macleod <duncan.macl...@ligo.org> License: GPL-3.0-or-later @@ -37,7 +37,7 @@ Requires-Dist: numpy>=1.19 Requires-Dist: python-dateutil Requires-Dist: requests -Requires-Dist: scipy>=1.5.0 +Requires-Dist: scipy>=1.6.0 Requires-Dist: tqdm>=4.10.0 Provides-Extra: test Requires-Dist: coverage[toml]>=5.0; extra == "test" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/_version.py new/gwpy-3.0.9/gwpy/_version.py --- old/gwpy-3.0.8/gwpy/_version.py 2024-01-12 11:46:17.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/_version.py 2024-07-12 18:24:35.000000000 +0200 @@ -12,5 +12,5 @@ __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE -__version__ = version = '3.0.8' -__version_tuple__ = version_tuple = (3, 0, 8) +__version__ = version = '3.0.9' +__version_tuple__ = version_tuple = (3, 0, 9) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/astro/range.py new/gwpy-3.0.9/gwpy/astro/range.py --- old/gwpy-3.0.8/gwpy/astro/range.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/astro/range.py 2024-07-12 18:24:15.000000000 +0200 @@ -25,7 +25,7 @@ from functools import wraps from math import pi -from scipy.integrate import trapz +from scipy.integrate import trapezoid from scipy.interpolate import interp1d from astropy import ( @@ -238,7 +238,7 @@ integrand = sensemon_range_psd(psd[frange], snr=snr, mass1=mass1, mass2=mass2, horizon=horizon) return (units.Quantity( - trapz(integrand.value, f.value[frange]), + trapezoid(integrand.value, f.value[frange]), unit=integrand.unit * units.Hertz, ) ** (1/2.)).to('Mpc') @@ -528,7 +528,7 @@ # calculate integrand and integrate integrand = burst_range_spectrum( psd[frange], snr=snr, energy=energy) ** 3 - out = trapz(integrand.value, f[frange]) + out = trapezoid(integrand.value, f[frange]) # normalize and return return (units.Quantity( out / (fmax - fmin), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/astro/tests/test_range.py new/gwpy-3.0.9/gwpy/astro/tests/test_range.py --- old/gwpy-3.0.8/gwpy/astro/tests/test_range.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/astro/tests/test_range.py 2024-07-12 18:24:15.000000000 +0200 @@ -24,7 +24,7 @@ import pytest from astropy import units -from scipy.integrate import trapz +from scipy.integrate import trapezoid from ... import astro from ...testing import utils @@ -71,7 +71,7 @@ r = astro.sensemon_range_psd(psd[frange]) assert isinstance(r, FrequencySeries) utils.assert_quantity_almost_equal( - trapz(r, r.frequencies) ** (1/2.), + trapezoid(r, r.frequencies) ** (1/2.), TEST_RESULTS['sensemon_range'], ) assert r.f0.value > 0 @@ -103,9 +103,8 @@ frange = (psd.frequencies.value < 4096) r = astro.inspiral_range_psd(psd[frange]) assert isinstance(r, FrequencySeries) - print(trapz(r, r.frequencies) ** (1/2.)) utils.assert_quantity_almost_equal( - trapz(r, r.frequencies) ** (1/2.), + trapezoid(r, r.frequencies) ** (1/2.), TEST_RESULTS['inspiral_range'], ) assert r.f0.value > 0 @@ -129,7 +128,7 @@ r = astro.burst_range_spectrum(psd[frange]) assert isinstance(r, FrequencySeries) utils.assert_quantity_almost_equal( - (trapz(r**3, f[frange]) / (400 * units.Hz)) ** (1/3.), + (trapezoid(r**3, f[frange]) / (400 * units.Hz)) ** (1/3.), TEST_RESULTS['burst_range'], ) assert r.f0.value > 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/cli/qtransform.py new/gwpy-3.0.9/gwpy/cli/qtransform.py --- old/gwpy-3.0.8/gwpy/cli/qtransform.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/cli/qtransform.py 2024-07-12 18:24:15.000000000 +0200 @@ -215,7 +215,7 @@ outseg = Segment(gps, gps).protract(args.plot[self.plot_num]) # use the precomputed ASD as the whitener if needed - if self.qxfrm_args.get("whiten"): + if self.qxfrm_args.get("whiten") is True: self.qxfrm_args["whiten"] = asd # This section tries to optimize the amount of data that is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/detector/units.py new/gwpy-3.0.9/gwpy/detector/units.py --- old/gwpy-3.0.8/gwpy/detector/units.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/detector/units.py 2024-07-12 18:24:15.000000000 +0200 @@ -167,6 +167,7 @@ # GW observatories like to record 'time' as the unit (units.Unit('second'), ( 'time', + 'time (s)', 'time [s]', 'Time [sec]', 'Time (sec)', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/io/datafind.py new/gwpy-3.0.9/gwpy/io/datafind.py --- old/gwpy-3.0.8/gwpy/io/datafind.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/io/datafind.py 2024-07-12 18:24:15.000000000 +0200 @@ -65,6 +65,7 @@ HIGH_PRIORITY_TYPE = re.compile("({})".format("|".join(( r'\A[A-Z]\d_HOFT_C\d\d(_T\d{7}_v\d)?\Z', # X1_HOFT_CXY r'\AV1Online\Z', + r'\AHoftOnline\Z', r'\AV1O[0-9]+([A-Z]+)?Repro[0-9]+[A-Z]+\Z', # V1OXReproXY )))) LOW_PRIORITY_TYPE = re.compile("({})".format("|".join(( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/io/ffldatafind.py new/gwpy-3.0.9/gwpy/io/ffldatafind.py --- old/gwpy-3.0.8/gwpy/io/ffldatafind.py 2022-06-27 14:00:09.000000000 +0200 +++ new/gwpy-3.0.9/gwpy/io/ffldatafind.py 2024-07-12 18:24:15.000000000 +0200 @@ -28,8 +28,9 @@ import os import re -from warnings import warn +from collections import defaultdict from functools import lru_cache +from warnings import warn from ligo.segments import ( segment, @@ -37,8 +38,10 @@ ) from .cache import ( + _CacheEntry, _iter_cache, cache_segments, + file_segment, read_cache_entry, ) @@ -123,10 +126,10 @@ def _find_ffls(basedir=None): """Find all readable FFL files. """ - ffls = {} + ffls = defaultdict(list) for path in _find_ffl_files(basedir=basedir): try: - ffls[_get_site_tag(path)] = path + ffls[_get_site_tag(path)].append(path) except ( OSError, # file is empty (or cannot be read at all) AttributeError, # last entry didn't match _SITE_REGEX @@ -135,8 +138,8 @@ return ffls -def _ffl_path(site, tag, basedir=None): - """Return the path of the FFL file for a given site and tag. +def _ffl_paths(site, tag, basedir=None): + """Return the paths of all FFL files for a given site and tag. """ try: return _find_ffls(basedir=basedir)[(site, tag)] @@ -147,15 +150,18 @@ @lru_cache() -def _read_ffl(site, tag, basedir=None): - """Read an FFL file as a list of `CacheEntry` objects - """ - ffl = _ffl_path(site, tag, basedir=basedir) - with open(ffl, "r") as fobj: - return [ - type(entry)(site, tag, entry.segment, entry.path) - for entry in _iter_cache(fobj, gpstype=float) - ] +def _read_ffls(site, tag, basedir=None): + """Read all FFL files for a given site and tag + as a list of `CacheEntry` objects. + """ + entries = [] + for ffl in _ffl_paths(site, tag, basedir=basedir): + with open(ffl, "r") as fobj: + entries.extend( + _CacheEntry(site, tag, entry.segment, entry.path) + for entry in _iter_cache(fobj, gpstype=float) + ) + return entries def _handle_error(action, message): @@ -261,7 +267,7 @@ span = segment(gpsstart, gpsend) cache = [ - e for e in _read_ffl(site, tag) if ( + e for e in _read_ffls(site, tag) if ( e.observatory == site and e.description == tag and e.segment.intersects(span) @@ -305,11 +311,16 @@ for a specific site and tag. """ try: - fflfile = _ffl_path(site, tag) + fflfiles = _ffl_paths(site, tag) except ValueError: # no readable FFL file urls = [] else: - urls = [read_cache_entry(_read_last_line(fflfile), gpstype=float)] + urls = [ + read_cache_entry(_read_last_line(fflfile), gpstype=float) + for fflfile in fflfiles + ] + if urls: # if multiple, find the latest one + urls = sorted(urls, key=file_segment)[-1:] if not urls: _handle_error(on_missing, "No files found") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/io/tests/test_ffldatafind.py new/gwpy-3.0.9/gwpy/io/tests/test_ffldatafind.py --- old/gwpy-3.0.8/gwpy/io/tests/test_ffldatafind.py 2022-06-27 14:00:09.000000000 +0200 +++ new/gwpy-3.0.9/gwpy/io/tests/test_ffldatafind.py 2024-07-12 18:24:15.000000000 +0200 @@ -96,9 +96,11 @@ # -- test ffl UI ------------ FFLS = { - "test.ffl": [ + "a/test.ffl": [ "/tmp/X-test-0-1.gwf 0 1 0 0", "/tmp/X-test-1-1.gwf 1 1 0 0", + ], + "b/test.ffl": [ "/tmp/X-test-2-1.gwf 2 1 0 0", ], "test2.ffl": [ @@ -114,7 +116,11 @@ "test-empty.ffl": [], "test-bad.ffl": ["badness"], } -TEST_URLS = [x.split()[0] for x in FFLS["test.ffl"]] +TEST_URLS = [ + x.split()[0] + for key in ("a/test.ffl", "b/test.ffl") + for x in FFLS[key] +] @pytest.fixture(autouse=True) @@ -124,6 +130,7 @@ """ for path, lines in FFLS.items(): ffl = tmp_path / path + ffl.parent.mkdir(parents=True, exist_ok=True) ffl.write_text("\n".join(lines)) with mock.patch.dict( "os.environ", @@ -190,7 +197,7 @@ assert ffldatafind.find_latest( "X", "test", - ) == sorted(x.split()[0] for x in FFLS["test.ffl"])[-1:] + ) == sorted(x.split()[0] for x in FFLS["b/test.ffl"])[-1:] @pytest.mark.parametrize(("on_missing", "ctx"), ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/plot/tex.py new/gwpy-3.0.9/gwpy/plot/tex.py --- old/gwpy-3.0.8/gwpy/plot/tex.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/plot/tex.py 2024-07-12 18:24:15.000000000 +0200 @@ -39,10 +39,12 @@ from matplotlib import (pyplot, rc_context) with rc_context({"text.usetex": True}): fig = pyplot.figure() - ax = fig.gca() - ax.set_xlabel(r"\LaTeX") - fig.canvas.draw() - pyplot.close(fig) + try: + ax = fig.gca() + ax.set_xlabel(r"\LaTeX") + fig.canvas.draw() + finally: + pyplot.close(fig) @lru_cache(maxsize=None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/signal/filter_design.py new/gwpy-3.0.9/gwpy/signal/filter_design.py --- old/gwpy-3.0.8/gwpy/signal/filter_design.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/signal/filter_design.py 2024-07-12 18:24:15.000000000 +0200 @@ -30,6 +30,7 @@ from astropy.units import (Unit, Quantity) +from ..types.array import COPY_IF_NEEDED from .window import (get_window, planck) __author__ = "Duncan Macleod <duncan.macl...@ligo.org>" @@ -89,7 +90,7 @@ kwargs.setdefault('pass_zero', False) if ws.shape == (1,): kwargs.setdefault('width', ws - wp) - kwargs.setdefault('nyq', sample_rate/2.) + kwargs.setdefault('fs', sample_rate) return signal.firwin(nt, wp, window=window, **kwargs) @@ -281,9 +282,9 @@ zpk : `tuple` digital version of input zpk """ - zeros = numpy.array(zeros, dtype=float, copy=False) + zeros = numpy.array(zeros, dtype=float, copy=COPY_IF_NEEDED) zeros = zeros[numpy.isfinite(zeros)] - poles = numpy.array(poles, dtype=float, copy=False) + poles = numpy.array(poles, dtype=float, copy=COPY_IF_NEEDED) gain = gain # convert from Hz to rad/s if needed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/signal/tests/test_filter_design.py new/gwpy-3.0.9/gwpy/signal/tests/test_filter_design.py --- old/gwpy-3.0.8/gwpy/signal/tests/test_filter_design.py 2022-06-27 14:00:09.000000000 +0200 +++ new/gwpy-3.0.9/gwpy/signal/tests/test_filter_design.py 2024-07-12 18:24:15.000000000 +0200 @@ -50,7 +50,7 @@ analog=False, ftype='cheby1', output='zpk', ) LOWPASS_FIR_100HZ = signal.firwin( - 30, 100, window='hamming', width=50., nyq=512., + 30, 100, window='hamming', width=50., fs=1024., ) HIGHPASS_IIR_100HZ = signal.iirdesign( @@ -60,7 +60,7 @@ analog=False, ftype='cheby1', output='zpk', ) HIGHPASS_FIR_100HZ = signal.firwin( - 45, 100, window='hamming', pass_zero=False, width=-100/3., nyq=512., + 45, 100, window='hamming', pass_zero=False, width=-100/3., fs=1024., ) BANDPASS_IIR_100HZ_200HZ = signal.iirdesign( @@ -70,7 +70,7 @@ analog=False, ftype='cheby1', output='zpk', ) BANDPASS_FIR_100HZ_200HZ = signal.firwin( - 45, (100, 200.), window='hamming', pass_zero=False, nyq=512., + 45, (100, 200.), window='hamming', pass_zero=False, fs=1024., ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/spectrogram/tests/test_spectrogram.py new/gwpy-3.0.9/gwpy/spectrogram/tests/test_spectrogram.py --- old/gwpy-3.0.8/gwpy/spectrogram/tests/test_spectrogram.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/spectrogram/tests/test_spectrogram.py 2024-07-12 18:24:15.000000000 +0200 @@ -175,11 +175,11 @@ # test simple filter a2 = array.filter(*zpk) - utils.assert_array_equal(array * fresp, a2) + utils.assert_quantity_sub_equal(array * fresp, a2) # test inplace filtering array.filter(lti, inplace=True) - utils.assert_array_equal(array, a2) + utils.assert_quantity_sub_equal(array, a2) # test errors with pytest.raises(TypeError): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/testing/fixtures.py new/gwpy-3.0.9/gwpy/testing/fixtures.py --- old/gwpy-3.0.8/gwpy/testing/fixtures.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/testing/fixtures.py 2024-07-12 18:24:15.000000000 +0200 @@ -52,25 +52,8 @@ # -- plotting ----------------------------------------------------------------- -def _test_usetex(): - """Return `True` if we can render figures using `text.usetex`. - """ - from matplotlib import pyplot - with rc_context(rc={'text.usetex': True}): - fig = pyplot.figure() - fig.gca() - try: - fig.canvas.draw() - except RuntimeError: - return False - else: - return True - finally: - pyplot.close(fig) - - SKIP_TEX = pytest.mark.skipif( - not has_tex() or not _test_usetex(), + not has_tex(), reason='TeX is not available', ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/testing/utils.py new/gwpy-3.0.9/gwpy/testing/utils.py --- old/gwpy-3.0.8/gwpy/testing/utils.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/testing/utils.py 2024-07-12 18:24:15.000000000 +0200 @@ -34,12 +34,14 @@ from astropy.time import Time -from ..utils.decorators import deprecated_function +from gwpy.io.cache import file_segment +from gwpy.utils.decorators import deprecated_function # -- useful constants --------------------------------------------------------- TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data') TEST_GWF_FILE = os.path.join(TEST_DATA_DIR, 'HLV-HW100916-968654552-1.gwf') +TEST_GWF_SPAN = file_segment(TEST_GWF_FILE) TEST_HDF5_FILE = os.path.join(TEST_DATA_DIR, 'HLV-HW100916-968654552-1.hdf') @@ -328,11 +330,18 @@ os.remove(name) -def test_read_write(data, format, - extension=None, autoidentify=True, - read_args=[], read_kw={}, - write_args=[], write_kw={}, - assert_equal=assert_array_equal, assert_kw={}): +def test_read_write( + data, + format, + extension=None, + autoidentify=True, + read_args=[], + read_kw={}, + write_args=[], + write_kw={}, + assert_equal=assert_quantity_sub_equal, + assert_kw={}, +): """Test that data can be written to and read from a file in some format Parameters diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/timeseries/io/cache.py new/gwpy-3.0.9/gwpy/timeseries/io/cache.py --- old/gwpy-3.0.8/gwpy/timeseries/io/cache.py 2022-06-27 14:00:09.000000000 +0200 +++ new/gwpy-3.0.9/gwpy/timeseries/io/cache.py 2024-07-12 18:24:15.000000000 +0200 @@ -19,22 +19,34 @@ """I/O utilities for reading `TimeSeries` from a `list` of file paths. """ -from ...io.cache import (FILE_LIKE, read_cache, file_segment, sieve) +from io import BytesIO +from math import inf +from os import PathLike + +from ...io.cache import ( + FILE_LIKE, + file_segment, + read_cache, + write_cache, +) from ...segments import Segment __author__ = "Duncan Macleod <duncan.macl...@ligo.org>" -def preformat_cache(cache, start=None, end=None): +def preformat_cache(cache, start=None, end=None, sort=file_segment): """Preprocess a `list` of file paths for reading. - - read the cache from the file (if necessary) - - sieve the cache to only include data we need + This function does the following: + + - read the list of paths cache file (if necessary), + - sort the cache in time order (if possible), + - sieve the cache to only include data we need. Parameters ---------- - cache : `list`, `str` - List of file paths, or path to a LAL-format cache file on disk. + cache : `list`, `str`, `pathlib.Path` + List of file paths, or path to a cache file. start : `~gwpy.time.LIGOTimeGPS`, `float`, `str`, optional GPS start time of required data, defaults to start of data found; @@ -44,31 +56,37 @@ GPS end time of required data, defaults to end of data found; any input parseable by `~gwpy.time.to_gps` is fine. + sort : `callable`, optional + A callable key function by which to sort the file paths. + Returns ------- modcache : `list` A parsed, sieved list of paths based on the input arguments. + + See also + -------- + gwpy.io.cache.read_cache + For details of how the sorting and sieving is implemented """ - # open cache file - if isinstance(cache, (str,) + FILE_LIKE): - return read_cache(cache, sort=file_segment, - segment=Segment(start, end)) - - # format existing cache file - cache = type(cache)(cache) # copy cache - - # sort cache - try: - cache.sort(key=file_segment) # sort - except ValueError: - # if this failed, then the sieving will also fail, but lets proceed - # anyway, since the user didn't actually ask us to do this (but - # its a very good idea) - return cache - - # sieve cache - if start is None: # start time of earliest file - start = file_segment(cache[0])[0] - if end is None: # end time of latest file - end = file_segment(cache[-1])[-1] - return sieve(cache, segment=Segment(start, end)) + # if given a list of paths, write it to a file-like structure + # so that we can use read_cache to do all the work + if not isinstance(cache, (str, PathLike) + FILE_LIKE): + cachef = BytesIO() + write_cache(cache, cachef) + cachef.seek(0) + cache = cachef + + # need start and end times to sieve the cache + if start is None: + start = -inf + if end is None: + end = +inf + + # read the cache + return read_cache( + cache, + coltype=type(start), + sort=sort, + segment=Segment(start, end), + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/timeseries/io/gwf/lalframe.py new/gwpy-3.0.9/gwpy/timeseries/io/gwf/lalframe.py --- old/gwpy-3.0.8/gwpy/timeseries/io/gwf/lalframe.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/timeseries/io/gwf/lalframe.py 2024-07-12 18:24:15.000000000 +0200 @@ -149,6 +149,14 @@ end = epoch + streamdur end = min(epoch + streamdur, lalutils.to_lal_ligotimegps(end)) duration = float(end - start) + if start >= (epoch + streamdur): + raise ValueError( + "cannot read data starting after stream ends", + ) + if duration < 0: + raise ValueError( + "cannot read data with negative duration", + ) # read data out = series_class.DictClass() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/timeseries/tests/test_io_cache.py new/gwpy-3.0.9/gwpy/timeseries/tests/test_io_cache.py --- old/gwpy-3.0.8/gwpy/timeseries/tests/test_io_cache.py 1970-01-01 01:00:00.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/timeseries/tests/test_io_cache.py 2024-07-12 18:24:15.000000000 +0200 @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# Copyright (C) Cardiff University 2023 +# +# This file is part of GWpy. +# +# GWpy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GWpy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GWpy. If not, see <http://www.gnu.org/licenses/>. + +"""Tests for :mod:`gwpy.timeseries.io.cache` +""" + +import pytest + +from ...io.cache import write_cache +from ..io import cache as ts_io_cache + + +@pytest.fixture +def cache(): + """List of files over which to test sorting/sieving. + """ + return [ + "/tmp/A-TEST-0-10.tmp", + "/tmp/A-TEST-10-10.tmp", + "/tmp/A-TEST-20-10.tmp", + "/tmp/A-TEST-30-5.tmp", + "/tmp/A-TEST-35-15.tmp", + ] + + +@pytest.fixture +def cache_file(tmp_path, cache): + """File version of `cache()`. + """ + path = tmp_path / "cache.txt" + write_cache(cache, path) + return path + + +@pytest.mark.parametrize("source", ("cache", "cache_file")) +@pytest.mark.parametrize(("start", "end", "idx"), [ + # use everything in the cache + (None, None, slice(None)), + # use only GPS time '25' onwards, which is cache[2:] + (25, None, slice(2, None)), + # use only up to GPS time '25', which is cache[:3] + (None, 25, slice(None, 3)), + # use interval [10, 35), which needs cache[1:4] + (10, 35, slice(1, 4)), +]) +def test_preformat_cache(request, cache, source, start, end, idx): + """Test that `gwpy.timeseries.io.cache.preformat_cache` works properly. + + Here `[start, end)` is a GPS segment, and `idx` the corresponding slice + needed to restrict the cache object. + + Loops over a variety of input arguments, using `request` to dynamically + loop over `cache` or `cache_file` as the input. + """ + assert ts_io_cache.preformat_cache( + request.getfixturevalue(source), # cache or cache_file + start=start, + end=end, + ) == cache[idx] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/timeseries/tests/test_timeseries.py new/gwpy-3.0.9/gwpy/timeseries/tests/test_timeseries.py --- old/gwpy-3.0.8/gwpy/timeseries/tests/test_timeseries.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/timeseries/tests/test_timeseries.py 2024-07-12 18:24:15.000000000 +0200 @@ -253,28 +253,29 @@ exclude=['channel']) @pytest.mark.parametrize('api', GWF_APIS) - def test_read_write_gwf_gps_errors(self, tmp_path, api): + def test_read_gwf_end_error(self, api): + """Test that reading past the end of available data fails. + """ fmt = "gwf" if api is None else "gwf." + api - array = self.create(name='TEST') - tmp = tmp_path / "test.gwf" - array.write(tmp, format=fmt) - - # check that reading past the end of the array fails - with pytest.raises((ValueError, RuntimeError)): + with pytest.raises(ValueError): self.TEST_CLASS.read( - tmp, - array.name, + utils.TEST_GWF_FILE, + "L1:LDAS-STRAIN", format=fmt, - start=array.span[1], + start=utils.TEST_GWF_SPAN[1], ) - # check that reading before the start of the array also fails - with pytest.raises((ValueError, RuntimeError)): + @pytest.mark.parametrize('api', GWF_APIS) + def test_read_gwf_negative_duration_error(self, api): + """Test that reading a negative duration fails. + """ + fmt = "gwf" if api is None else "gwf." + api + with pytest.raises(ValueError): self.TEST_CLASS.read( - tmp, - array.name, + utils.TEST_GWF_FILE, + "L1:LDAS-STRAIN", format=fmt, - end=array.span[0]-1, + end=utils.TEST_GWF_SPAN[0]-1, ) @pytest.mark.parametrize('api', GWF_APIS) @@ -1073,18 +1074,22 @@ fgram = gw150914.fftgram(1) fs = int(gw150914.sample_rate.value) f, t, sxx = signal.spectrogram( - gw150914, fs, + gw150914, + fs, window='hann', nperseg=fs, mode='complex', ) utils.assert_array_equal(gw150914.t0.value + t, fgram.xindex.value) utils.assert_array_equal(f, fgram.yindex.value) - utils.assert_array_equal(sxx.T, fgram) + utils.assert_array_equal(sxx.T, fgram.value) + def test_fftgram_overlap(self, gw150914): fgram = gw150914.fftgram(1, overlap=0.5) + fs = int(gw150914.sample_rate.value) f, t, sxx = signal.spectrogram( - gw150914, fs, + gw150914, + fs, window='hann', nperseg=fs, noverlap=fs//2, @@ -1092,7 +1097,7 @@ ) utils.assert_array_equal(gw150914.t0.value + t, fgram.xindex.value) utils.assert_array_equal(f, fgram.yindex.value) - utils.assert_array_equal(sxx.T, fgram) + utils.assert_array_equal(sxx.T, fgram.value) def test_spectral_variance(self, gw150914): variance = gw150914.spectral_variance(.5, method="median") @@ -1381,7 +1386,9 @@ def test_convolve(self): data = self.TEST_CLASS( - signal.hann(1024), sample_rate=512, epoch=-1 + signal.get_window("hann", 1024), + sample_rate=512, + epoch=-1, ) filt = numpy.array([1, 0]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/types/array.py new/gwpy-3.0.9/gwpy/types/array.py --- old/gwpy-3.0.8/gwpy/types/array.py 2022-06-27 14:00:09.000000000 +0200 +++ new/gwpy-3.0.9/gwpy/types/array.py 2024-07-12 18:24:15.000000000 +0200 @@ -34,6 +34,11 @@ import numpy from astropy.units import Quantity +try: + from astropy.utils.compat.numpycompat import COPY_IF_NEEDED +except ImportError: # astropy < 6.1 + from astropy.utils import minversion + COPY_IF_NEEDED = None if minversion(numpy, "2.0.0.dev") else False from ..detector import Channel from ..detector.units import parse_unit @@ -119,8 +124,16 @@ unit = parse_unit(unit, parse_strict='warn') # create new array - new = super().__new__(cls, value, unit=unit, dtype=dtype, copy=False, - order=order, subok=subok, ndmin=ndmin) + new = super().__new__( + cls, + value, + unit=unit, + dtype=dtype, + copy=COPY_IF_NEEDED, + order=order, + subok=subok, + ndmin=ndmin, + ) # explicitly copy here to get ownership of the data, # see (astropy/astropy#7244) @@ -397,7 +410,7 @@ out = super().__array_ufunc__(function, method, *inputs, **kwargs) # if a ufunc returns a scalar, return a Quantity if not out.ndim: - return Quantity(out, copy=False) + return Quantity(out, copy=COPY_IF_NEEDED) # otherwise return an array return out diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/types/index.py new/gwpy-3.0.9/gwpy/types/index.py --- old/gwpy-3.0.8/gwpy/types/index.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/types/index.py 2024-07-12 18:24:15.000000000 +0200 @@ -23,6 +23,8 @@ from astropy.units import Quantity +from .array import COPY_IF_NEEDED + class Index(Quantity): """1-D `~astropy.units.Quantity` array for indexing a `Series` @@ -57,11 +59,11 @@ """ if dtype is None: dtype = max( - numpy.array(start, subok=True, copy=False).dtype, - numpy.array(step, subok=True, copy=False).dtype, + numpy.array(start, subok=True, copy=COPY_IF_NEEDED).dtype, + numpy.array(step, subok=True, copy=COPY_IF_NEEDED).dtype, ) - start = Quantity(start, dtype=dtype, copy=False) - step = Quantity(step, dtype=dtype, copy=False).to(start.unit) + start = Quantity(start, dtype=dtype, copy=COPY_IF_NEEDED) + step = Quantity(step, dtype=dtype, copy=COPY_IF_NEEDED).to(start.unit) stop = start + step * num return cls( numpy.arange( @@ -71,7 +73,7 @@ dtype=dtype, )[:num], unit=start.unit, - copy=False, + copy=COPY_IF_NEEDED, ) @property diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy/utils/tests/test_sphinx_zenodo.py new/gwpy-3.0.9/gwpy/utils/tests/test_sphinx_zenodo.py --- old/gwpy-3.0.8/gwpy/utils/tests/test_sphinx_zenodo.py 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/gwpy/utils/tests/test_sphinx_zenodo.py 2024-07-12 18:24:15.000000000 +0200 @@ -19,6 +19,8 @@ """Tests for :mod:`gwpy.utils.sphinx.zenodo`. """ +from functools import wraps + import pytest import requests @@ -83,8 +85,23 @@ """.strip() +def pytest_skip_rate_limit(func): + """Execute `func` but skip if it raises a rate limit error + """ + @wraps(func) + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except requests.HTTPError as exc: # pragma: no cover + if str(exc).startswith("403 Client Error: rate limit exceeded"): + pytest.skip(str(exc)) + raise + return wrapper + + @pytest.fixture @pytest_skip_network_error +@pytest_skip_rate_limit def latest(): """Get the latest release of GWpy from the GitHub API. """ @@ -97,6 +114,7 @@ @pytest_skip_network_error +@pytest_skip_rate_limit def test_zenodo_format_citations_latest(latest): """Check that :func:`gwpy.utils.sphinx.zenodo.format_citations` includes the latest actual release in the output. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy.egg-info/PKG-INFO new/gwpy-3.0.9/gwpy.egg-info/PKG-INFO --- old/gwpy-3.0.8/gwpy.egg-info/PKG-INFO 2024-01-12 11:46:18.000000000 +0100 +++ new/gwpy-3.0.9/gwpy.egg-info/PKG-INFO 2024-07-12 18:24:35.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: gwpy -Version: 3.0.8 +Version: 3.0.9 Summary: A python package for gravitational-wave astrophysics Author-email: Duncan Macleod <duncan.macl...@ligo.org> License: GPL-3.0-or-later @@ -37,7 +37,7 @@ Requires-Dist: numpy>=1.19 Requires-Dist: python-dateutil Requires-Dist: requests -Requires-Dist: scipy>=1.5.0 +Requires-Dist: scipy>=1.6.0 Requires-Dist: tqdm>=4.10.0 Provides-Extra: test Requires-Dist: coverage[toml]>=5.0; extra == "test" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy.egg-info/SOURCES.txt new/gwpy-3.0.9/gwpy.egg-info/SOURCES.txt --- old/gwpy-3.0.8/gwpy.egg-info/SOURCES.txt 2024-01-12 11:46:18.000000000 +0100 +++ new/gwpy-3.0.9/gwpy.egg-info/SOURCES.txt 2024-07-12 18:24:35.000000000 +0200 @@ -323,6 +323,7 @@ gwpy/timeseries/io/gwf/lalframe.py gwpy/timeseries/tests/__init__.py gwpy/timeseries/tests/test_core.py +gwpy/timeseries/tests/test_io_cache.py gwpy/timeseries/tests/test_io_gwf_framecpp.py gwpy/timeseries/tests/test_io_gwf_lalframe.py gwpy/timeseries/tests/test_io_losc.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/gwpy.egg-info/requires.txt new/gwpy-3.0.9/gwpy.egg-info/requires.txt --- old/gwpy-3.0.8/gwpy.egg-info/requires.txt 2024-01-12 11:46:18.000000000 +0100 +++ new/gwpy-3.0.9/gwpy.egg-info/requires.txt 2024-07-12 18:24:35.000000000 +0200 @@ -10,7 +10,7 @@ numpy>=1.19 python-dateutil requests -scipy>=1.5.0 +scipy>=1.6.0 tqdm>=4.10.0 [astro] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gwpy-3.0.8/pyproject.toml new/gwpy-3.0.9/pyproject.toml --- old/gwpy-3.0.8/pyproject.toml 2024-01-12 11:35:36.000000000 +0100 +++ new/gwpy-3.0.9/pyproject.toml 2024-07-12 18:24:15.000000000 +0200 @@ -48,7 +48,7 @@ "numpy >=1.19", "python-dateutil", "requests", - "scipy >=1.5.0", + "scipy >=1.6.0", "tqdm >=4.10.0", ] ++++++ gwpy-numpy-2.0-types.patch ++++++ >From 1b95818798f0aaa3f501930159b538083bf749f1 Mon Sep 17 00:00:00 2001 From: Duncan Macleod <macleo...@cardiff.ac.uk> Date: Thu, 25 Jul 2024 11:43:16 +0100 Subject: [PATCH] gwpy.table: fix use of numpy types float_ and unicode_ were aliases for a while and were removed in numpy 2 closes #1776 --- gwpy/table/io/ligolw.py | 2 +- gwpy/table/tests/test_io_ligolw.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gwpy/table/io/ligolw.py b/gwpy/table/io/ligolw.py index f69976405..282e6a3bd 100644 --- a/gwpy/table/io/ligolw.py +++ b/gwpy/table/io/ligolw.py @@ -58,7 +58,7 @@ try: except ImportError: pass else: - NUMPY_TYPE_MAP[LIGOTimeGPS] = numpy.float_ + NUMPY_TYPE_MAP[LIGOTimeGPS] = numpy.float64 # -- utilities ---------------------------------------------------------------- diff --git a/gwpy/table/tests/test_io_ligolw.py b/gwpy/table/tests/test_io_ligolw.py index f7090629a..60e17775e 100644 --- a/gwpy/table/tests/test_io_ligolw.py +++ b/gwpy/table/tests/test_io_ligolw.py @@ -70,7 +70,7 @@ def test_to_astropy_table_empty(): tab = EventTable(llwtable, columns=["peak", "ifo"]) assert set(tab.colnames) == {"peak", "ifo"} assert tab['peak'].dtype.type is numpy.object_ - assert tab['ifo'].dtype.type is numpy.unicode_ + assert tab['ifo'].dtype.type is numpy.str_ @pytest.mark.requires("ligo.lw.lsctables") -- GitLab