BUNPC / pysnirf2

Python package for reading, writing and validating Shared Near Infrared Spectroscopy Format (SNIRF) files
GNU General Public License v3.0
15 stars 11 forks source link

AttributeError: 'numpy.ndarray' object has no attribute 'decode' #31

Closed fangq closed 2 years ago

fangq commented 2 years ago

I tried to use pysnirf2 validator to test one of the samples files I previously generated

https://github.com/fNIRS/snirf-samples/blob/master/basic/neuro_run01.snirf

but it gives me the following error

fangq@taote:/drives/taote1/users/fangq/git/Project/github/snirf-samples/basic$ python3
Python 3.6.9 (default, Mar 15 2022, 13:55:28) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pysnirf2 import validateSnirf
>>> result = validateSnirf(r'neuro_run01.snirf');
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/users/fangq/.local/lib/python3.6/site-packages/pysnirf2/pysnirf2.py", line 5445, in validateSnirf
    with Snirf(path) as snirf:
  File "/home/users/fangq/.local/lib/python3.6/site-packages/pysnirf2/pysnirf2.py", line 5036, in __init__
    self._formatVersion = _read_string(self._h['formatVersion'])
  File "/home/users/fangq/.local/lib/python3.6/site-packages/pysnirf2/pysnirf2.py", line 294, in _read_string
    return str(dataset[0].decode('ascii'))
AttributeError: 'numpy.ndarray' object has no attribute 'decode'

>>> from pysnirf2 import Snirf
>>> snirf = Snirf(r'neuro_run01.snirf')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/users/fangq/.local/lib/python3.6/site-packages/pysnirf2/pysnirf2.py", line 5036, in __init__
    self._formatVersion = _read_string(self._h['formatVersion'])
  File "/home/users/fangq/.local/lib/python3.6/site-packages/pysnirf2/pysnirf2.py", line 294, in _read_string
    return str(dataset[0].decode('ascii'))
AttributeError: 'numpy.ndarray' object has no attribute 'decode'

I could open it and read the field using h5py

>>> import h5py
>>> f = h5py.File('neuro_run01.snirf', 'r')
>>> 
>>> list(f.keys())
['formatVersion', 'nirs']
>>> f['formatVersion']
<HDF5 dataset "formatVersion": shape (1, 3), type "|S1">

any quick fixes?

sstucker commented 2 years ago

Hi, glad to see you using this

The array not having 'decode' means this was supposed to be a char array but was something else, so this is an issue of format on the end of the Snirf file perhaps. Nothing in pysnirf will work with this file until I add logic which loads this particular string without complaining.

What program generated this file? And how is the string formatted (in terms of HDF5)

I am happy to do the sleuthing and push a quick fix if you send the offending file along

fangq commented 2 years ago

@sstucker, thanks for the quick response - the file was created in matlab, using my toolbox EasyH5 (saveh5 function) via the savesnirf wrapper called in this line -

https://github.com/fNIRS/snirf-samples/blob/master/basic/updatesnirffromsrc.m#L21

as you can see, I use JSON/JSNIRF as the "source code" to create the matlab struct, and then save the struct to an HDF5 file. my matlab data type to H5 dataset type mapping table is here

https://github.com/fangq/easyh5/blob/master/saveh5.m#L374-L387

sstucker commented 2 years ago

To be clear this is a fixed length HDF5 string as opposed to a variable one?

I can't see how this code would create strings differently than the old Homer fixed length strings, which load fine.

fangq commented 2 years ago

I believe it was loaded ok, but for some reason, the variable holding the string, dataset[0], was converted to a numpy.ndarray in pysnirf2, thus, it can no longer call decode() (which only works for a string)