Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
@weiglszonja (#1486)
- Improved warning text when dimensions are not matched in `TimeSeries`, `ElectricalSeries`, and `RoiResponseSeries`.
@rly (#1491)
- Added ``pywnb.validate.get_cached_namespaces_to_validate`` function to facilitate validation of files against cached
namespaces when using ``pynwb.validate`` from Python directly. @oruebel (#1432)

### Documentation and tutorial enhancements:
- Added tutorial on annotating data via ``TimeIntervals``. @oruebel (#1390)
Expand Down
58 changes: 46 additions & 12 deletions src/pynwb/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,51 @@ def _validate_helper(**kwargs):
return (errors is not None and len(errors) > 0)


def get_cached_namespaces_to_validate(path):
"""
Determine the most specific namespace(s) (i.e., extensions) that are cached in the given
NWB file that should be used for validation.

Example
-------

The following example illustrates how we can use this function to validate against namespaces
cached in a file. This is useful, e.g., when a file was created using an extension

>>> from pynwb import validate
>>> from pynwb.validate import get_cached_namespaces_to_validate
>>> path = "my_nwb_file.nwb"
>>> validate_namespaces, manager, cached_namespaces = get_cached_namespaces_to_validate(path)
>>> with NWBHDF5IO(path, "r", manager=manager) as reader:
>>> errors = []
>>> for ns in validate_namespaces:
>>> errors += validate(io=reader, namespace=ns)

:param path: Path for the NWB file
:return: Tuple with:
- List of strings with the most specific namespace(s) to use for validation.
- BuildManager object for opening the file for validation
- Dict with the full result from NWBHDF5IO.load_namespaces
"""
catalog = NamespaceCatalog(NWBGroupSpec, NWBDatasetSpec, NWBNamespace)
ns_deps = NWBHDF5IO.load_namespaces(catalog, path)
# determine which namespaces are the most specific (i.e. extensions) and validate against those
s = set(ns_deps.keys())
for k in ns_deps:
s -= ns_deps[k].keys()
# TODO remove this workaround for issue https://github.com/NeurodataWithoutBorders/pynwb/issues/1357
s.discard('hdmf-experimental') # remove validation of hdmf-experimental for now
namespaces = sorted(s)

if len(namespaces) > 0:
tm = TypeMap(catalog)
manager = BuildManager(tm)
else:
manager = None

return namespaces, manager, ns_deps


def main(): # noqa: C901

ep = """
Expand Down Expand Up @@ -69,21 +114,10 @@ def main(): # noqa: C901
continue

if args.cached_namespace:
catalog = NamespaceCatalog(NWBGroupSpec, NWBDatasetSpec, NWBNamespace)
ns_deps = NWBHDF5IO.load_namespaces(catalog, path)
s = set(ns_deps.keys()) # determine which namespaces are the most
for k in ns_deps: # specific (i.e. extensions) and validate
s -= ns_deps[k].keys() # against those
# TODO remove this workaround for issue https://github.com/NeurodataWithoutBorders/pynwb/issues/1357
if 'hdmf-experimental' in s:
s.remove('hdmf-experimental') # remove validation of hdmf-experimental for now
namespaces = list(sorted(s))
namespaces, manager, ns_deps = get_cached_namespaces_to_validate(path)
if len(namespaces) > 0:
tm = TypeMap(catalog)
manager = BuildManager(tm)
specloc = "cached namespace information"
else:
manager = None
namespaces = [CORE_NAMESPACE]
specloc = "pynwb namespace information"
print("The file {} has no cached namespace information. "
Expand Down