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

Reply via email to