Skip to content

Round-trip write/read GWF fails when timeseries name and channel differ

When writing a TimeSeries to GWF when the name and channel attributes differ, reading the data from the new file raises an unusual error:

>>> import numpy
>>> from gwpy.timeseries import TimeSeries
>>> data = TimeSeries(
...     numpy.random.random(10),
...     channel="X1:TEST",
...     name="test",
... )
>>> data.write("test.gwf", format="gwf.framecpp", type="proc")
>>> new = type(data).read("test.gwf", "X1:TEST")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-5ff61904bd82> in <module>
----> 1 new = type(data).read("test.gwf", "X1:TEST")

~/git/gwpy-fork5/gwpy/timeseries/core.py in read(cls, source, *args, **kwargs)
    312         -----"""
    313         from .io.core import read as timeseries_reader
--> 314         return timeseries_reader(cls, source, *args, **kwargs)
    315
    316     def write(self, target, *args, **kwargs):

~/git/gwpy-fork5/gwpy/timeseries/io/core.py in read(cls, source, *args, **kwargs)
     48     )
     49     # read
---> 50     return io_read_multi(joiner, cls, source, *args, **kwargs)
     51
     52

~/git/gwpy-fork5/gwpy/io/mp.py in read_multi(flatten, cls, source, *args, **kwargs)
     91     # read files
     92     output = mp_utils.multiprocess_with_queues(
---> 93         nproc, _read_single_file, inputs, verbose=verbose, unit='files')
     94
     95     # raise exceptions (from multiprocessing, single process raises inline)

~/git/gwpy-fork5/gwpy/utils/mp.py in multiprocess_with_queues(nproc, func, inputs, verbose, **progress_kw)
    121                     pbar.update(1)
    122
--> 123         return list(map(_inner, inputs))
    124
    125     # -------------------------------------------

~/git/gwpy-fork5/gwpy/utils/mp.py in _inner(x)
    116         def _inner(x):
    117             try:
--> 118                 return func(x)
    119             finally:
    120                 if pbar:

~/git/gwpy-fork5/gwpy/io/mp.py in _read_single_file(bundle)
    119     fobj, cls, nproc, args, kwargs = bundle
    120     try:
--> 121         return fobj, io_read(cls, fobj, *args, **kwargs)
    122     # pylint: disable=broad-except,redefine-in-handler
    123     except Exception as exc:

~/opt/miniconda3/envs/py37/lib/python3.7/site-packages/astropy/io/registry.py in read(cls, format, *args, **kwargs)
    521
    522         reader = get_reader(format, cls)
--> 523         data = reader(*args, **kwargs)
    524
    525         if not isinstance(data, cls):

~/git/gwpy-fork5/gwpy/timeseries/io/gwf/__init__.py in read_(*args, **kwargs)
    399         fmt = 'gwf.{}'.format(get_default_gwf_api())
    400         reader = get_reader(fmt, container)
--> 401         return reader(*args, **kwargs)
    402
    403     def write_(*args, **kwargs):

~/git/gwpy-fork5/gwpy/timeseries/io/gwf/__init__.py in read_timeseries(source, channel, *args, **kwargs)
    285         """Read `TimeSeries` from GWF source
    286         """
--> 287         return read_timeseriesdict(source, [channel], *args, **kwargs)[channel]
    288
    289     def read_statevector(source, channel, *args, **kwargs):

~/git/gwpy-fork5/gwpy/timeseries/io/gwf/__init__.py in read_timeseriesdict(source, channels, start, end, dtype, resample, gap, pad, nproc, series_class, **kwargs)
    269                     out[name] = numpy.require(out[name], requirements=['O'])
    270             out.append(libread_(src, channels, start=start, end=end,
--> 271                                 series_class=series_class, **kwargs),
    272                        gap=gap, pad=pad, copy=False)
    273

~/git/gwpy-fork5/gwpy/timeseries/io/gwf/framecpp.py in read(source, channels, start, end, scaled, type, series_class)
    116         # read frame
    117         out.append(read_gwf(file_, channels, start=start, end=end, ctype=ctype,
--> 118                             scaled=scaled, series_class=series_class),
    119                    copy=False)
    120     return out

~/git/gwpy-fork5/gwpy/timeseries/io/gwf/framecpp.py in read_gwf(filename, channels, start, end, scaled, ctype, series_class)
    207
    208         # if we have all of the data we want, stop now
--> 209         if all(span in out[channel].span for channel in out):
    210             break
    211

~/git/gwpy-fork5/gwpy/timeseries/io/gwf/framecpp.py in <genexpr>(.0)
    207
    208         # if we have all of the data we want, stop now
--> 209         if all(span in out[channel].span for channel in out):
    210             break
    211

AttributeError: 'numpy.ndarray' object has no attribute 'span'

This is all because the FrProcData structure is created using the channel string, while the FrVect structures are tagged using the name string. We should just the name for everything, I think.