Skip to content

Commit a4c8efe

Browse files
Merge branch 'dev' into document_formatter
2 parents ca97bc0 + 63fbf8e commit a4c8efe

22 files changed

+187
-216
lines changed

nwbinspector/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from .register_checks import available_checks, Importance
22
from .nwbinspector import inspect_nwb, inspect_all, load_config
3-
from .checks.nwbfile_metadata import *
3+
from .checks.behavior import *
4+
from .checks.ecephys import *
45
from .checks.general import *
6+
from .checks.image_series import *
57
from .checks.nwb_containers import *
6-
from .checks.time_series import *
7-
from .checks.tables import *
8-
from .checks.ecephys import *
8+
from .checks.nwbfile_metadata import *
99
from .checks.ogen import *
10-
from .checks.image_series import *
11-
from .checks.behavior import *
10+
from .checks.ophys import *
11+
from .checks.tables import *
12+
from .checks.time_series import *

nwbinspector/checks/ecephys.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,21 @@ def check_electrical_series_dims(electrical_series: ElectricalSeries):
3737
if data_shape and len(data_shape) == 2 and data_shape[1] != len(electrodes.data):
3838
if data_shape[0] == len(electrodes.data):
3939
return InspectorMessage(
40-
message="The second dimension of data does not match the length of electrodes, "
41-
"but instead the first does. Data is oriented incorrectly and should be transposed."
40+
message=(
41+
"The second dimension of data does not match the length of electrodes, "
42+
"but instead the first does. Data is oriented incorrectly and should be transposed."
43+
)
4244
)
4345
return InspectorMessage(
44-
message="The second dimension of data does not match the length of electrodes. Your "
45-
"data may be transposed."
46+
message=(
47+
"The second dimension of data does not match the length of electrodes. Your " "data may be transposed."
48+
)
4649
)
4750

4851

4952
@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=ElectricalSeries)
5053
def check_electrical_series_reference_electrodes_table(electrical_series: ElectricalSeries):
54+
"""Check that the 'electrodes' of an ElectricalSeries references the ElectrodesTable."""
5155
if electrical_series.electrodes.table.name != "electrodes":
5256
return InspectorMessage(message="electrodes does not reference an electrodes table.")
5357

nwbinspector/checks/icephys.py

Lines changed: 0 additions & 28 deletions
This file was deleted.

nwbinspector/checks/image_series.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ def check_image_series_external_file_valid(image_series: ImageSeries):
1313
if image_series.external_file is None:
1414
return
1515
nwbfile_path = Path(get_nwbfile_path_from_internal_object(obj=image_series))
16-
print(nwbfile_path)
1716
for file_path in image_series.external_file:
1817
if not Path(file_path).is_absolute() and not (nwbfile_path.parent / file_path).exists():
1918
yield InspectorMessage(

nwbinspector/checks/nwb_containers.py

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ def check_large_dataset_compression(nwb_container: NWBContainer, gb_lower_bound:
1616
Will only return an inspector warning if the size of the h5py.Dataset is larger than 20 GB.
1717
"""
1818
for field in getattr(nwb_container, "fields", dict()).values():
19-
if (
20-
isinstance(field, h5py.Dataset)
21-
and field.compression is None
22-
and field.size * field.dtype.itemsize > gb_lower_bound * 1e9
23-
):
19+
if not isinstance(field, h5py.Dataset):
20+
continue
21+
if field.compression is None and field.size * field.dtype.itemsize > gb_lower_bound * 1e9:
2422
return InspectorMessage(
2523
severity=Severity.HIGH,
2624
message=f"{os.path.split(field.name)[1]} is a large uncompressed dataset! Please enable compression.",
@@ -40,9 +38,10 @@ def check_small_dataset_compression(
4038
Will only return an inspector warning if the size of the h5py.Dataset is larger than bytes_threshold.
4139
"""
4240
for field in getattr(nwb_container, "fields", dict()).values():
41+
if not isinstance(field, h5py.Dataset):
42+
continue
4343
if (
44-
isinstance(field, h5py.Dataset)
45-
and field.compression is None
44+
field.compression is None
4645
and mb_lower_bound * 1e6 < field.size * field.dtype.itemsize < gb_upper_bound * 1e9
4746
):
4847
if field.size * field.dtype.itemsize > gb_severity_threshold * 1e9:
@@ -56,28 +55,3 @@ def check_small_dataset_compression(
5655
"dataset."
5756
),
5857
)
59-
60-
61-
# TODO: break up extra logic
62-
# def check_data_uniqueness(ts):
63-
# """Check whether data of a timeseries has few unique values and can be stored in a better way."""
64-
# uniq = np.unique(ts.data)
65-
# if len(uniq) == 1:
66-
# error_code = "A101"
67-
# print("- %s: '%s' %s data has all values = %s" % (error_code, ts.name, type(ts).__name__, uniq[0]))
68-
# elif np.array_equal(uniq, [0.0, 1.0]):
69-
# if ts.data.dtype != bool and type(ts) is TimeSeries:
70-
# # if a base TimeSeries object has 0/1 data but is not using booleans
71-
# # note that this tests only base TimeSeries objects. TimeSeries subclasses may require numeric/int/etc.
72-
# error_code = "A101"
73-
# print(
74-
# "- %s: '%s' %s data only contains values 0 and 1. Consider changing to type boolean instead of %s"
75-
# % (error_code, ts.name, type(ts).__name__, ts.data.dtype)
76-
# )
77-
# elif len(uniq) == 2:
78-
# print(
79-
# "- NOTE: '%s' %s data has only 2 unique values: %s. Consider storing the data as boolean."
80-
# % (ts.name, type(ts).__name__, uniq)
81-
# )
82-
# elif len(uniq) <= 4:
83-
# print("- NOTE: '%s' %s data has only unique values %s" % (ts.name, type(ts).__name__, uniq))

nwbinspector/checks/nwbfile_metadata.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ def check_doi_publications(nwbfile: NWBFile):
7979

8080
if not nwbfile.related_publications:
8181
return
82-
8382
for publication in nwbfile.related_publications:
8483
if isinstance(publication, bytes):
8584
publication = publication.decode()
@@ -100,8 +99,10 @@ def check_subject_age(subject: Subject):
10099
return InspectorMessage(message="Subject is missing age and date_of_birth.")
101100
elif not re.fullmatch(duration_regex, subject.age):
102101
return InspectorMessage(
103-
message=f"Subject age, '{subject.age}', does not follow ISO 8601 duration format, e.g. 'P2Y' for 2 years "
104-
f"or 'P23W' for 23 weeks."
102+
message=(
103+
f"Subject age, '{subject.age}', does not follow ISO 8601 duration format, e.g. 'P2Y' for 2 years "
104+
"or 'P23W' for 23 weeks."
105+
)
105106
)
106107

107108

@@ -135,8 +136,10 @@ def check_subject_species_latin_binomial(subject: Subject):
135136
"""Check if the subject species follows latin binomial form."""
136137
if subject.species and not re.fullmatch(species_regex, subject.species):
137138
return InspectorMessage(
138-
message=f"Subject species '{subject.species}' should be in latin binomial form, e.g. 'Mus musculus' and "
139-
f"'Homo sapiens'",
139+
message=(
140+
f"Subject species '{subject.species}' should be in latin binomial form, e.g. 'Mus musculus' and "
141+
"'Homo sapiens'"
142+
),
140143
)
141144

142145

@@ -145,6 +148,8 @@ def check_processing_module_name(processing_module: ProcessingModule):
145148
"""Check if the name of a processing module is of a valid modality."""
146149
if processing_module.name not in PROCESSING_MODULE_CONFIG:
147150
return InspectorMessage(
148-
f"Processing module is named {processing_module.name}. It is recommended to use the "
149-
f"schema module names: {', '.join(PROCESSING_MODULE_CONFIG)}"
151+
message=(
152+
f"Processing module is named {processing_module.name}. It is recommended to use the "
153+
f"schema module names: {', '.join(PROCESSING_MODULE_CONFIG)}"
154+
)
150155
)

nwbinspector/checks/ophys.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
"""Check functions specific to optical electrophysiology neurodata types."""
2-
from pynwb.ophys import RoiResponseSeries, PlaneSegmentation, OpticalChannel, ImagingPlane
2+
from pynwb.ophys import (
3+
RoiResponseSeries,
4+
PlaneSegmentation,
5+
OpticalChannel,
6+
ImagingPlane,
7+
)
38

49
from hdmf.utils import get_data_shape
510

@@ -19,30 +24,46 @@ def check_roi_response_series_dims(roi_response_series: RoiResponseSeries):
1924
if data_shape and len(data_shape) == 2 and data_shape[1] != len(rois.data):
2025
if data_shape[0] == len(rois.data):
2126
return InspectorMessage(
22-
message="The second dimension of data does not match the length of rois, "
23-
"but instead the first does. Data is oriented incorrectly and should be transposed."
27+
message=(
28+
"The second dimension of data does not match the length of rois, "
29+
"but instead the first does. Data is oriented incorrectly and should be transposed."
30+
)
2431
)
2532
return InspectorMessage(
2633
message="The second dimension of data does not match the length of rois. Your data may be transposed."
2734
)
2835

2936

30-
@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=RoiResponseSeries)
31-
def check_roi_response_series_link_to_plane_segmentation(roi_response_series: RoiResponseSeries):
37+
@register_check(
38+
importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=RoiResponseSeries
39+
)
40+
def check_roi_response_series_link_to_plane_segmentation(
41+
roi_response_series: RoiResponseSeries,
42+
):
3243
"""Check that each ROI response series links to a plane segmentation."""
3344
if not isinstance(roi_response_series.rois.table, PlaneSegmentation):
34-
return InspectorMessage(message="rois field does not point to a PlaneSegmentation table.")
45+
return InspectorMessage(
46+
message="rois field does not point to a PlaneSegmentation table."
47+
)
3548

3649

37-
@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=OpticalChannel)
50+
@register_check(
51+
importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=OpticalChannel
52+
)
3853
def check_emission_lambda_in_nm(optical_channel: OpticalChannel):
3954
"""Check that emission lambda is in feasible range for unit nanometers."""
4055
if optical_channel.emission_lambda < MIN_LAMBDA:
41-
return InspectorMessage(f"emission lambda of {optical_channel.emission_lambda} should be in units of nm.")
56+
return InspectorMessage(
57+
f"emission lambda of {optical_channel.emission_lambda} should be in units of nm."
58+
)
4259

4360

44-
@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=ImagingPlane)
61+
@register_check(
62+
importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=ImagingPlane
63+
)
4564
def check_excitation_lambda_in_nm(imaging_plane: ImagingPlane):
4665
"""Check that emission lambda is in feasible range for unit nanometers."""
4766
if imaging_plane.excitation_lambda < MIN_LAMBDA:
48-
return InspectorMessage(f"excitation lambda of {imaging_plane.excitation_lambda} should be in units of nm.")
67+
return InspectorMessage(
68+
f"excitation lambda of {imaging_plane.excitation_lambda} should be in units of nm."
69+
)

0 commit comments

Comments
 (0)