pynwb icon indicating copy to clipboard operation
pynwb copied to clipboard

[Bug]: `pynwb.validate` can not check with `NWBZarrIO`

Open MGAMZ opened this issue 3 months ago • 1 comments

What happened?

The pynwb.validate is designed to operate on both NWBHDF5IO or NWBZarrIO. But I found the current implementation cannot work properly when checking a Zarr-compressed NWB file. It seems to _validate_single_file incorrectly invoked the API of NWBZarrIO.

The issue is similar to https://github.com/hdmf-dev/hdmf-zarr/issues/293, which also reports a validation error when checking a zarr-compressed nwb file. But its traceback seems to be different.

Steps to Reproduce

Create a zarr-compressed NWB file.

from hdmf_zarr import NWBZarrIO
with NWBZarrIO(output_path, 'w') as io:
    io.write(nwbfile)

Make sure that the file can be read by NWBZarrIO

print(NWBZarrIO.can_read(output_path))

should print True


Then, validate it:

import pynwb
pynwb.validate(path=output_path)

There should be errors, which is further attached below.

Traceback

The traceback varies depending on the configuration of use_cached_namespaces.

use_cached_namespaces=True (Default)

KeyError                                  Traceback (most recent call last)
File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/spec/namespace.py:466, in NamespaceCatalog.__load_namespace(self, namespace, reader, resolve)
    465 try:
--> 466     inc_ns = self.get_namespace(s['namespace'])
    467 except KeyError as e:

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:578, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
    577 pargs = _check_args(args, kwargs)
--> 578 return func(args[0], **pargs)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/spec/namespace.py:317, in NamespaceCatalog.get_namespace(self, **kwargs)
    316 if ret is None:
--> 317     raise KeyError("'%s' not a namespace" % name)
    318 return ret

KeyError: "'core' not a namespace"

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

ValueError                                Traceback (most recent call last)
Cell In[9], line 3
      1 import pynwb
----> 3 pynwb.validate(path=output_path, use_cached_namespaces=True)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:582, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
    580 def func_call(*args, **kwargs):
    581     pargs = _check_args(args, kwargs)
--> 582     return func(**pargs)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/pynwb/validation.py:163, in validate(**kwargs)
    161         validation_errors +=  _validate_single_file(path=p, **kwargs)
    162 else:
--> 163     validation_errors = _validate_single_file(path=path, **kwargs)
    165 return validation_errors

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/pynwb/validation.py:181, in _validate_single_file(**kwargs)
      0 <Error retrieving source code with stack_data see ipython/ipython#13598>

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/pynwb/validation.py:70, in get_cached_namespaces_to_validate(path, driver, aws_region, io)
     68     from pynwb import _get_backend
     69     backend_io = _get_backend(path, method=driver)
---> 70     namespace_dependencies = backend_io.load_namespaces(namespace_catalog=catalog, 
     71                                                         path=path, 
     72                                                         driver=driver, 
     73                                                         aws_region=aws_region)
     75 # Determine which namespaces are the most specific (i.e. extensions) and validate against those
     76 candidate_namespaces = set(namespace_dependencies.keys())

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:578, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
    576 def func_call(*args, **kwargs):
    577     pargs = _check_args(args, kwargs)
--> 578     return func(args[0], **pargs)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf_zarr/backend.py:285, in ZarrIO.load_namespaces(cls, namespace_catalog, path, storage_options, namespaces)
    283 ns_group = ns_group[latest_version]
    284 reader = ZarrSpecReader(ns_group)
--> 285 namespace_catalog.load_namespaces("namespace", reader=reader)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:578, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
    576 def func_call(*args, **kwargs):
    577     pargs = _check_args(args, kwargs)
--> 578     return func(args[0], **pargs)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/spec/namespace.py:578, in NamespaceCatalog.load_namespaces(self, **kwargs)
    576     # now load specs into namespace
    577     for ns in to_load:
--> 578         ret[ns['name']] = self.__load_namespace(ns, r, resolve=resolve)
    579     self.__included_specs[ns_path_key] = ret
    581 # warn if there are any ignored namespaces

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/spec/namespace.py:468, in NamespaceCatalog.__load_namespace(self, namespace, reader, resolve)
    466     inc_ns = self.get_namespace(s['namespace'])
    467 except KeyError as e:
--> 468     raise ValueError("Could not load namespace '%s'" % s['namespace']) from e
    469 if types_to_load is None:
    470     types_to_load = inc_ns.get_registered_types()  # load all types in namespace

ValueError: Could not load namespace 'core'

use_cached_namespaces=False

TypeError                                 Traceback (most recent call last)
Cell In[10], line 3
      1 import pynwb
----> 3 pynwb.validate(path=output_path, use_cached_namespaces=False)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:582, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
    580 def func_call(*args, **kwargs):
    581     pargs = _check_args(args, kwargs)
--> 582     return func(**pargs)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/pynwb/validation.py:163, in validate(**kwargs)
    161         validation_errors +=  _validate_single_file(path=p, **kwargs)
    162 else:
--> 163     validation_errors = _validate_single_file(path=path, **kwargs)
    165 return validation_errors

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/pynwb/validation.py:202, in _validate_single_file(**kwargs)
    200     from pynwb import _get_backend
    201     backend_io = _get_backend(path, method=driver)
--> 202     io = backend_io(**io_kwargs)
    204 # check namespaces are accurate
    205 if namespace is not None:

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:577, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
    576 def func_call(*args, **kwargs):
--> 577     pargs = _check_args(args, kwargs)
    578     return func(args[0], **pargs)

File ~/miniforge3/envs/dbci/lib/python3.13/site-packages/hdmf/utils.py:570, in docval.<locals>.dec.<locals>._check_args(args, kwargs)
    568     if parse_err:
    569         msg = '%s: %s' % (func.__qualname__, ', '.join(parse_err))
--> 570         raise ExceptionType(msg)
    572 return parsed['args']

TypeError: NWBZarrIO.__init__: unrecognized argument: 'driver'

Operating System

Linux

Python Executable

Conda

Python Version

3.13

Package Versions

environment_for_issue.txt

Code of Conduct

MGAMZ avatar Sep 09 '25 06:09 MGAMZ

Thanks for reporting this issue and for the detailed breakdown @MGAMZ. Validation of NWB Zarr files is not yet fully supported, but is something we are working on! There are a couple of remaining updates needed in hdmf-zarr.

I will let you know here when we have an update.

stephprince avatar Sep 18 '25 22:09 stephprince