NeurodataWithoutBorders / aqnwb

A C++ API for data acquisition using the NWB Format
https://neurodatawithoutborders.github.io/aqnwb/
Other
3 stars 0 forks source link

Add file validation CI #21

Closed oruebel closed 5 months ago

oruebel commented 5 months ago

To ensure compatibility with PyNWB and the NWB format more broadly, it would be useful to run the PyNWB validator or the NWBInspector on the NWB files generated by the test suite. Running the validator on test_nwb_file.h5 generated by running ctest in the build directory currently shows the following issues:

python -m pynwb.validate test_nwb_file.h5
<frozen runpy>:128: RuntimeWarning: 'pynwb.validate' found in sys.modules after import of package 'pynwb', but prior to execution of 'pynwb.validate'; this may result in unpredictable behaviour
/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/backends/hdf5/h5tools.py:213: UserWarning: No cached namespaces found in test_nwb_file.h5
  warnings.warn(msg)
The file test_nwb_file.h5 has no cached namespace information. Falling back to PyNWB namespace information.
Validating test_nwb_file.h5 against PyNWB namespace information using namespace 'core'.
 - found the following errors:
root/file_create_date (file_create_date): incorrect type - expected 'isodatetime', got 'utf'
root/file_create_date (file_create_date): incorrect shape - expected an array of shape '[None]', got non-array data '2024-04-21T22:33:38-0800'
root/session_start_time (session_start_time): incorrect type - expected 'isodatetime', got 'utf'
root/timestamps_reference_time (timestamps_reference_time): incorrect type - expected 'isodatetime', got 'utf'
oruebel commented 5 months ago

root/file_create_date (file_create_date): incorrect shape - expected an array of shape '[None]', got non-array data '2024-04-21T22:33:38-0800'

file_create_date should be an array of strings. The idea behind this is, that each time a file is being modified, a new date is appended to the list with the time the file was modified (see https://nwb-schema.readthedocs.io/en/latest/format.html#id150)

oruebel commented 5 months ago

root/file_create_date (file_create_date): incorrect type - expected 'isodatetime', got 'utf' root/session_start_time (session_start_time): incorrect type - expected 'isodatetime', got 'utf' root/timestamps_reference_time (timestamps_reference_time): incorrect type - expected 'isodatetime', got 'utf'

When trying to open the test_nwb_file.h5 with PyNWB it looks like it fails to convert the date. At first glance, I think there may be a ":" missing in the last part of the isodatetime string, i.e., aqnbw writes 2024-04-21T23:09:46-0800 but I think it should be 2024-04-21T23:09:46-08:00

>>> from pynwb import NWBHDF5IO
>>> f = NWBHDF5IO('test_nwb_file.h5' , mode='r')
/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/backends/hdf5/h5tools.py:213: UserWarning: No cached namespaces found in test_nwb_file.h5
  warnings.warn(msg)
>>> n = f.read()
Traceback (most recent call last):
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/dateutil/parser/_parser.py", line 649, in parse
    ret = self._build_naive(res, default)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/dateutil/parser/_parser.py", line 1235, in _build_naive
    naive = default.replace(**repl)
            ^^^^^^^^^^^^^^^^^^^^^^^
ValueError: day is out of range for month

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/utils.py", line 644, in func_call
    return func(args[0], **pargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/Devel/nwb/pynwb/src/pynwb/__init__.py", line 326, in read
    file = super().read(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/backends/hdf5/h5tools.py", line 479, in read
    return super().read(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/utils.py", line 644, in func_call
    return func(args[0], **pargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/backends/io.py", line 60, in read
    container = self.__manager.construct(f_builder)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/utils.py", line 644, in func_call
    return func(args[0], **pargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/build/manager.py", line 284, in construct
    result = self.__type_map.construct(builder, self, None)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/utils.py", line 644, in func_call
    return func(args[0], **pargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/build/manager.py", line 795, in construct
    return obj_mapper.construct(builder, build_manager, parent)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/utils.py", line 644, in func_call
    return func(args[0], **pargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/build/objectmapper.py", line 1247, in construct
    override = self.__get_override_carg(argname, builder, manager)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/hdmf/build/objectmapper.py", line 531, in __get_override_carg
    return func(self, *remaining_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/Devel/nwb/pynwb/src/pynwb/io/file.py", line 172, in dateconversion_list
    dates = list(map(dateutil_parse, datestr))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/dateutil/parser/_parser.py", line 1368, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/oruebel/miniforge3/envs/py4nwb/lib/python3.11/site-packages/dateutil/parser/_parser.py", line 651, in parse
    six.raise_from(ParserError(str(e) + ": %s", timestr), e)
  File "<string>", line 3, in raise_from
dateutil.parser._parser.ParserError: day is out of range for month: 0