Skip to content

Commit

Permalink
Support only latest PyNWB (#510)
Browse files Browse the repository at this point in the history
* remove past PyNWB version references

* explictly pin lower bound

* restore accidental context removal

* fix image test import

* Update CHANGELOG.md

Co-authored-by: Steph Prince <[email protected]>

---------

Co-authored-by: CodyCBakerPhD <[email protected]>
Co-authored-by: Steph Prince <[email protected]>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent bdf3548 commit e3cc7e2
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 135 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
### Improvements
* Removed the `robust_ros3_read` utility helper. [#506](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/506)
* Simplified the `nwbinspector.testing` configuration framework. [#509](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/509)
* Cleaned old references to non-recent PyNWB and HDMF versions. Current policy is that latest NWB Inspector releases should only support compatibility with latest PyNWB and HDMF. [#510](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/510)



# v0.5.2
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pynwb
pynwb>=2.8 # NWB Inspector should always be used with most recent minor versions of PyNWB
hdmf-zarr
fsspec
s3fs
Expand Down
3 changes: 1 addition & 2 deletions src/nwbinspector/_dandi_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,8 @@ def inspect_url(
h5py.File(name=byte_stream) as file,
pynwb.NWBHDF5IO(file=file) as io,
):
if not skip_validate:
if skip_validate is False:
validation_errors = pynwb.validate(io=io)

for validation_error in validation_errors:
yield InspectorMessage(
message=validation_error.reason,
Expand Down
25 changes: 6 additions & 19 deletions src/nwbinspector/_nwb_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import pynwb
from natsort import natsorted
from packaging.version import Version
from tqdm import tqdm

from . import available_checks, configure_checks
Expand All @@ -20,7 +19,6 @@
OptionalListOfStrings,
PathType,
calculate_number_of_cpu,
get_package_version,
)


Expand Down Expand Up @@ -73,8 +71,8 @@ def inspect_all(
all available CPUs minus x.
Set to 1 (also the default) to disable.
skip_validate : bool, optional
Skip the PyNWB validation step. This may be desired for older NWBFiles (< schema version v2.10).
The default is False, which is also recommended.
Skip the PyNWB validation step.
The default is False, which is recommended.
progress_bar : bool, optional
Display a progress bar while scanning NWBFiles.
Defaults to True.
Expand Down Expand Up @@ -232,8 +230,8 @@ def inspect_nwbfile(
nwbfile_path : FilePathType
Path to the NWB file on disk or on S3.
skip_validate : bool
Skip the PyNWB validation step. This may be desired for older NWBFiles (< schema version v2.10).
The default is False, which is also recommended.
Skip the PyNWB validation step.
The default is False, which is recommended.
checks : list, optional
List of checks to run.
config : dict
Expand Down Expand Up @@ -269,7 +267,7 @@ def inspect_nwbfile(
filterwarnings(action="ignore", message="No cached namespaces found in .*")
filterwarnings(action="ignore", message="Ignoring cached namespace .*")

if not skip_validate and get_package_version("pynwb") >= Version("2.2.0"):
if not skip_validate:
validation_error_list, _ = pynwb.validate(paths=[nwbfile_path])
for validation_namespace_errors in validation_error_list:
for validation_error in validation_namespace_errors:
Expand All @@ -282,17 +280,6 @@ def inspect_nwbfile(
)

with pynwb.NWBHDF5IO(path=nwbfile_path, mode="r", load_namespaces=True) as io:
if not skip_validate and get_package_version("pynwb") < Version("2.2.0"):
validation_errors = pynwb.validate(io=io)
for validation_error in validation_errors:
yield InspectorMessage(
message=validation_error.reason,
importance=Importance.PYNWB_VALIDATION,
check_function_name=validation_error.name,
location=validation_error.location,
file_path=nwbfile_path,
)

try:
in_memory_nwbfile = io.read()

Expand Down Expand Up @@ -321,7 +308,7 @@ def _intercept_in_vitro_protein(nwbfile_object: pynwb.NWBFile, checks: Optional[
If the special 'protein' subject_id is specified, return a truncated list of checks to run.
This is a temporary method for allowing upload of certain in vitro data to DANDI and
is expected to replaced in future versions.
is expected to be replaced in future versions.
"""
subject_related_check_names = [
"check_subject_exists",
Expand Down
64 changes: 31 additions & 33 deletions src/nwbinspector/checks/_images.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
"""Checks specific to the Images neurodata type."""

from packaging.version import Version
from pynwb.base import Images
from pynwb.image import IndexSeries

from .._registration import Importance, InspectorMessage, register_check
from ..utils import get_package_version

# The Images neurodata type was unavailable prior to PyNWB v.2.1.0
if get_package_version(name="pynwb") >= Version("2.1.0"):
from pynwb.base import Images

@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=Images)
def check_order_of_images_unique(images: Images):
"""Check that all the values in the order_of_images field of an Images object are unique."""
if images.order_of_images is None:
return
if not len(set(images.order_of_images)) == len(images.order_of_images):
return InspectorMessage(message="order_of_images should have unique values.")

@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=Images)
def check_order_of_images_len(images: Images):
"""Check that all the values in the order_of_images field of an Images object are unique."""
if images.order_of_images is None:
return
if not len(images.order_of_images) == len(images.images):
return InspectorMessage(
message=f"Length of order_of_images ({len(images.order_of_images)}) does not match the number of "
f"images ({len(images.images)})."
)

@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=IndexSeries)
def check_index_series_points_to_image(index_series: IndexSeries):
if index_series.indexed_timeseries is not None:
return InspectorMessage(
message="Pointing an IndexSeries to a TimeSeries will be deprecated. Please point to an Images "
"container instead."
)


@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=Images)
def check_order_of_images_unique(images: Images):
"""Check that all the values in the order_of_images field of an Images object are unique."""
if images.order_of_images is None:
return
if not len(set(images.order_of_images)) == len(images.order_of_images):
return InspectorMessage(message="order_of_images should have unique values.")


@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=Images)
def check_order_of_images_len(images: Images):
"""Check that all the values in the order_of_images field of an Images object are unique."""
if images.order_of_images is None:
return
if not len(images.order_of_images) == len(images.images):
return InspectorMessage(
message=f"Length of order_of_images ({len(images.order_of_images)}) does not match the number of "
f"images ({len(images.images)})."
)


@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=IndexSeries)
def check_index_series_points_to_image(index_series: IndexSeries):
if index_series.indexed_timeseries is not None:
return InspectorMessage(
message="Pointing an IndexSeries to a TimeSeries will be deprecated. Please point to an Images "
"container instead."
)
15 changes: 0 additions & 15 deletions tests/unit_tests/test_icephys.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import pytest
from packaging.version import Version
from pynwb.device import Device
from pynwb.icephys import IntracellularElectrode

from nwbinspector import Importance, InspectorMessage
from nwbinspector.checks import check_intracellular_electrode_cell_id_exists
from nwbinspector.utils import get_package_version

PYNWB_VERSION_LOWER_2_1_0 = get_package_version(name="pynwb") < Version("2.1.0")
PYNWB_VERSION_LOWER_SKIP_REASON = "This test requires PyNWB>=2.1.0"


@pytest.mark.skipif(PYNWB_VERSION_LOWER_2_1_0, reason=PYNWB_VERSION_LOWER_SKIP_REASON)
def test_pass_check_intracellular_electrode_cell_id_exists():
device = Device(name="device")
ielec = IntracellularElectrode(name="ielec", cell_id="123", device=device, description="an intracellular electrode")
assert check_intracellular_electrode_cell_id_exists(ielec) is None


@pytest.mark.skipif(PYNWB_VERSION_LOWER_2_1_0, reason=PYNWB_VERSION_LOWER_SKIP_REASON)
def test_fail_check_intracellular_electrode_cell_id_exists():
device = Device(name="device")
ielec = IntracellularElectrode(name="ielec", device=device, description="an intracellular electrode")
Expand All @@ -30,10 +22,3 @@ def test_fail_check_intracellular_electrode_cell_id_exists():
object_name="ielec",
location="/",
)


@pytest.mark.skipif(not PYNWB_VERSION_LOWER_2_1_0, reason="This test requires PyNWB<2.1.0")
def test_skip_check_for_lower_versions():
device = Device(name="device")
ielec = IntracellularElectrode(name="ielec", device=device, description="an intracellular electrode")
assert check_intracellular_electrode_cell_id_exists(ielec) is None
15 changes: 1 addition & 14 deletions tests/unit_tests/test_images.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import numpy as np
import pytest
from packaging.version import Version
from pynwb import TimeSeries
from pynwb.base import ImageReferences, Images
from pynwb.image import GrayscaleImage, IndexSeries

from nwbinspector import Importance, InspectorMessage
Expand All @@ -10,15 +9,8 @@
check_order_of_images_len,
check_order_of_images_unique,
)
from nwbinspector.utils import get_package_version

HAVE_IMAGES = get_package_version(name="pynwb") >= Version("2.1.0")
skip_reason = "You must have PyNWB>=v2.1.0 to run these tests!"
if HAVE_IMAGES:
from pynwb.base import ImageReferences, Images


@pytest.mark.skipif(not HAVE_IMAGES, reason=skip_reason)
def test_check_order_of_images_unique():
imgs = [GrayscaleImage(name=f"image{i}", data=np.random.randn(10, 10)) for i in range(5)]
img_refs = ImageReferences(name="order_of_images", data=imgs + [imgs[0]])
Expand All @@ -34,7 +26,6 @@ def test_check_order_of_images_unique():
)


@pytest.mark.skipif(not HAVE_IMAGES, reason=skip_reason)
def test_pass_check_order_of_images_unique():
imgs = [GrayscaleImage(name=f"image{i}", data=np.random.randn(10, 10)) for i in range(5)]
img_refs = ImageReferences(name="order_of_images", data=imgs)
Expand All @@ -43,7 +34,6 @@ def test_pass_check_order_of_images_unique():
assert check_order_of_images_unique(images) is None


@pytest.mark.skipif(not HAVE_IMAGES, reason=skip_reason)
def test_check_order_of_images_len():
imgs = [GrayscaleImage(name=f"image{i}", data=np.random.randn(10, 10)) for i in range(5)]
img_refs = ImageReferences(name="order_of_images", data=imgs + [imgs[0]])
Expand All @@ -59,7 +49,6 @@ def test_check_order_of_images_len():
)


@pytest.mark.skipif(not HAVE_IMAGES, reason=skip_reason)
def test_pass_check_order_of_images_len():
imgs = [GrayscaleImage(name=f"image{i}", data=np.random.randn(10, 10)) for i in range(5)]
img_refs = ImageReferences(name="order_of_images", data=imgs)
Expand All @@ -68,7 +57,6 @@ def test_pass_check_order_of_images_len():
assert check_order_of_images_len(images) is None


@pytest.mark.skipif(not HAVE_IMAGES, reason=skip_reason)
def test_pass_check_index_series_points_to_image():
gs_img = GrayscaleImage(
name="random grayscale",
Expand All @@ -95,7 +83,6 @@ def test_pass_check_index_series_points_to_image():
assert check_index_series_points_to_image(idx_series) is None


@pytest.mark.skipif(not HAVE_IMAGES, reason=skip_reason)
def test_fail_check_index_series_points_to_image():
time_series = TimeSeries(
name="TimeSeries",
Expand Down
Loading

0 comments on commit e3cc7e2

Please sign in to comment.