Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade validation methods #1911

Open
wants to merge 35 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
dbadbd5
reconcile io path validator differences
stephprince Apr 17, 2024
fe81ad3
make io and path output the same
stephprince Apr 18, 2024
18826f8
update tests for io validation
stephprince Apr 18, 2024
923c1d3
add test that io and path output is same
stephprince Apr 18, 2024
41d9b9d
update tests for io output with status
stephprince May 29, 2024
8c921a3
add validate helper function and fix status tracking
stephprince May 29, 2024
95556a8
update arguments and status checks
stephprince May 29, 2024
87b1f1e
fix test comparing io and path outputs
stephprince May 29, 2024
6a748a5
update error message for io inputs
stephprince May 29, 2024
250513e
add tests to compare all io and path outputs
stephprince May 29, 2024
76a4f0f
remove script for testing
stephprince May 29, 2024
593c330
Merge branch 'dev' into upgrade-validator
stephprince Nov 12, 2024
25fc892
add initial json export option
stephprince Nov 13, 2024
6caa46b
update validator inputs and outputs, remove hdf5io references
stephprince Nov 13, 2024
4c48c67
update tests for non status output
stephprince Nov 13, 2024
216315a
add tests for json validator output
stephprince Nov 13, 2024
7c5f20f
move pynwb.validate into validation module
stephprince Nov 13, 2024
d791f6f
update json report
stephprince Nov 13, 2024
096013e
add validation entry point
stephprince Nov 13, 2024
ea4af1e
separate cli and validation function files
stephprince Nov 13, 2024
c14931a
update validation tutorial
stephprince Nov 21, 2024
c2a9522
move get_backend to pynwb init
stephprince Nov 21, 2024
2224b45
update example validation for new io behavior
stephprince Nov 23, 2024
f0912f3
update ruff ignores
stephprince Nov 23, 2024
8263b77
fix test comments
stephprince Nov 23, 2024
aa7b4ee
Merge branch 'dev' into upgrade-validator
stephprince Nov 23, 2024
8e5aa62
update CHANGELOG
stephprince Nov 27, 2024
72779d5
add tests for _get_backend
stephprince Nov 27, 2024
be666b6
update backend imports for optional zarr
stephprince Nov 27, 2024
0745bd2
Merge branch 'dev' into upgrade-validator
stephprince Nov 27, 2024
f319e88
fix test name
stephprince Nov 27, 2024
12bc84c
update test filename
stephprince Nov 27, 2024
35181ed
close io after validation
stephprince Dec 16, 2024
d2f7561
fix test assertion
stephprince Dec 16, 2024
11cc232
add condition for ros3 validation
stephprince Dec 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@

## PyNWB 3.0.0 (Upcoming)

### Breaking changes
- The validation methods have been updated with multiple breaking changes. @stephprince [#1911](https://github.com/NeurodataWithoutBorders/pynwb/pull/1911)
- The behavior of `pynwb.validate(io=...)` now matches the behavior of `pynwb.validate(path=...)`. In previous pynwb versions, `pynwb.validate(io=...)` did not use the cached namespaces during validation. To obtain the same behavior as in previous versions, you can update the function call to `pynwb.validate(io=..., used_cached_namespaces=False)`
- The validate module has been renamed to `validation.py`. The validate method can be
imported using `import pynwb; pynwb.validate` or `from pynwb.validation import validate`

### Enhancements and minor changes
- Added support for NWB schema 2.8.0. @rly [#2001](https://github.com/NeurodataWithoutBorders/pynwb/pull/2001)
- Removed `SpatialSeries.bounds` field that was not functional. This will be fixed in a future release. @rly [#1907](https://github.com/NeurodataWithoutBorders/pynwb/pull/1907), [#1996](https://github.com/NeurodataWithoutBorders/pynwb/pull/1996)
- Added support for `NWBFile.was_generated_by` field. @stephprince [#1924](https://github.com/NeurodataWithoutBorders/pynwb/pull/1924)
- Added support for `model_number`, `model_name`, and `serial_number` fields to `Device`. @stephprince [#1997](https://github.com/NeurodataWithoutBorders/pynwb/pull/1997)
- Deprecated `EventWaveform` neurodata type. @rly [#1940](https://github.com/NeurodataWithoutBorders/pynwb/pull/1940)
- Deprecated `ImageMaskSeries` neurodata type. @rly [#1941](https://github.com/NeurodataWithoutBorders/pynwb/pull/1941)
- Added enhancements to the validation CLI. @stephprince [#1911](https://github.com/NeurodataWithoutBorders/pynwb/pull/1911)
- Added an entry point for the validation module. You can now use `pynwb-validate "file.nwb"`.
- Added the `--json-file-path` CLI argument to output validation results in a machine readable format.

## PyNWB 2.8.3 (November 19, 2024)

Expand Down
28 changes: 19 additions & 9 deletions docs/source/validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
Validating NWB files
====================

.. note::

The pynwb validation CLI checks for structural compliance of NWB files with the NWB schema.
It is recommended to use the `NWBInspector CLI <https://nwbinspector.readthedocs.io/en/dev/>`_
for more comprehensive validation of both structural compliance with the NWB schema and
compliance of data with NWB best practices. The NWBInspector runs both PyNWB validation as
described here and additional data checks.


Validating NWB files is handled by a command-line tool available in :py:mod:`~pynwb`.
The validator can be invoked like so:

.. code-block:: bash

python -m pynwb.validate test.nwb
pynwb-validate test.nwb

If the file contains no NWB extensions, then this command will validate the file ``test.nwb`` against the
*core* NWB specification. On success, the output will be:
Expand All @@ -29,35 +38,36 @@ within the ``test.nwb`` file.

.. code-block:: bash

python -m pynwb.validate -n ndx-my-extension test.nwb
pynwb-validate -n ndx-my-extension test.nwb

To validate against the version of the **core** NWB specification that is included with the installed version of
PyNWB, use the ``--no-cached-namespace`` flag. This can be useful in validating files against newer or older versions
of the **core** NWB specification that are installed with newer or older versions of PyNWB.

.. code-block:: bash

python -m pynwb.validate --no-cached-namespace test.nwb
pynwb-validate --no-cached-namespace test.nwb

.. Last updated 8/13/2021
.. code-block:: text

$python -m pynwb.validate --help
usage: validate.py [-h] [-n NS] [-lns] [--cached-namespace | --no-cached-namespace] paths [paths ...]
$pynwb-validate --help
usage: pynwb-validate [-h] [-lns] [-n NS] [--json-file-path JSON_FILE_PATH] [--no-cached-namespace] paths [paths ...]

Validate an NWB file

positional arguments:
paths NWB file paths

optional arguments:
options:
-h, --help show this help message and exit
-n NS, --ns NS the namespace to validate against
-lns, --list-namespaces
List the available namespaces and exit.
--cached-namespace Use the cached namespace (default).
-n NS, --ns NS the namespace to validate against
--json-file-path JSON_FILE_PATH
Write json output to this location.
--no-cached-namespace
Don't use the cached namespace.
Use the PyNWB loaded namespace (true) or use the cached namespace (false; default).

If --ns is not specified, validate against all namespaces in the NWB file.

Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ dynamic = ["version"] # the build backend will compute the version dynamically f
"Homepage" = "https://github.com/NeurodataWithoutBorders/pynwb"
"Bug Tracker" = "https://github.com/NeurodataWithoutBorders/pynwb/issues"

[project.scripts]
pynwb-validate = "pynwb.validation_cli:validation_cli"

[tool.hatch.version]
source = "vcs"

Expand Down Expand Up @@ -111,7 +114,7 @@ line-length = 120
"docs/gallery/*" = ["E402", "T201"]
"src/*/__init__.py" = ["F401"]
"src/pynwb/_version.py" = ["T201"]
"src/pynwb/validate.py" = ["T201"]
"src/pynwb/validation_cli.py" = ["T201"]
"scripts/*" = ["T201"]

# "test_gallery.py" = ["T201"] # Uncomment when test_gallery.py is created
Expand Down
23 changes: 22 additions & 1 deletion src/pynwb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
CORE_NAMESPACE = 'core'

from .spec import NWBDatasetSpec, NWBGroupSpec, NWBNamespace # noqa E402
from .validate import validate # noqa: F401, E402
from .validation import validate # noqa: F401, E402

try:
# see https://effigies.gitlab.io/posts/python-packaging-2023/
Expand Down Expand Up @@ -354,6 +354,27 @@
return __TYPE_MAP.get_dt_container_cls(neurodata_type, namespace)


@docval({'name': 'path', 'type': str, 'doc': 'the neurodata_type to get the NWBContainer class for'},
{"name": "method", "type": str, "doc": "the method to use when opening the file", 'default': None},
is_method=False)
def _get_backend(path: str, method: str = None):
if method == "ros3":
return NWBHDF5IO # TODO - add additional conditions for other streaming methods

Check warning on line 362 in src/pynwb/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/pynwb/__init__.py#L362

Added line #L362 was not covered by tests

try:
from hdmf_zarr import NWBZarrIO
backend_io_classes = [NWBHDF5IO, NWBZarrIO]

Check warning on line 366 in src/pynwb/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/pynwb/__init__.py#L366

Added line #L366 was not covered by tests
except ImportError:
backend_io_classes = [NWBHDF5IO]

backend_options = [b for b in backend_io_classes if b.can_read(path=path)]
if len(backend_options) == 0:
raise ValueError(f"Could not find an IO to read the file '{path}'. If you are trying to read "
f"a Zarr file, make sure you have hdmf-zarr installed.")
else:
return backend_options[0]


class NWBHDF5IO(_HDF5IO):

@staticmethod
Expand Down
8 changes: 4 additions & 4 deletions src/pynwb/testing/testh5io.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,12 @@ def getContainer(self, nwbfile):
def validate(self):
""" Validate the created files """
if os.path.exists(self.filename):
errors, _ = pynwb_validate(paths=[self.filename])
errors = pynwb_validate(path=self.filename)
if errors:
raise Exception("\n".join(errors))

if os.path.exists(self.export_filename):
errors, _ = pynwb_validate(paths=[self.export_filename])
errors = pynwb_validate(path=self.export_filename)
if errors:
raise Exception("\n".join(errors))

Expand Down Expand Up @@ -366,11 +366,11 @@ def roundtripExportContainer(self, cache_spec=True):
def validate(self):
"""Validate the created files."""
if os.path.exists(self.filename):
errors, _ = pynwb_validate(paths=[self.filename])
errors = pynwb_validate(path=self.filename)
if errors:
raise Exception("\n".join(errors))

if os.path.exists(self.export_filename):
errors, _ = pynwb_validate(paths=[self.export_filename])
errors = pynwb_validate(path=self.export_filename)
if errors:
raise Exception("\n".join(errors))
Loading
Loading