Skip to content

Commit de341fa

Browse files
CodyCBakerPhDrly
andauthored
Add in vitro support (#431)
* add injection and test * extend form to allow other subject ID value for DANDI organization * adjust test docstring * expand docs and changelog * remove mock until we move to new pynwb permanently * swap from invitro to protein * Update tests/test_inspector.py Co-authored-by: Ryan Ly <[email protected]> --------- Co-authored-by: Ryan Ly <[email protected]>
1 parent 8f741eb commit de341fa

File tree

4 files changed

+59
-4
lines changed

4 files changed

+59
-4
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
* Use cached extension namespaces when calling pynwb validate instead of just the core namespace. [#425](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/425)
1010

11+
### Improvements
12+
13+
* Added automatic suppression of certain subject related checks when inspecting files using the "dandi" configuration that have a `subject_id` that starts with the keyphrase "protein"; _e.g._, "proteinCaMPARI3" to indicate the _in vitro_ subject of the experiment is a purified CaMPARI3 protein.
14+
15+
16+
1117
# v0.4.30
1218

1319
### Fixes

docs/best_practices/nwbfile_metadata.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ A ``subject_id`` is required for upload to the :dandi-archive:`DANDI archive <>`
184184
not intended for DANDI upload, if the :ref:`nwb-schema:sec-Subject` is specified at all it should be given a
185185
``subject_id`` for reference.
186186

187+
In the special case of *in vitro* studies where the 'subject' of scientific interest was not a tissue sample obtained from a living subject but was instead a purified protein, this will be annotated by prepending the keyphrase "protein" to the subject ID; *e.g*, "proteinCaMPARI3". In the case where the *in vitro* experiment is performed on an extracted or cultured biological sample, the other subject attributes (such as age and sex) should be specified as their values at the time the sample was collected.
188+
187189
Check function: :py:meth:`~nwbinspector.checks.nwbfile_metadata.check_subject_id_exists`
188190

189191

src/nwbinspector/nwbinspector.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,38 @@ def inspect_nwbfile(
604604
)
605605

606606

607+
# TODO: deprecate once subject types and dandi schemas have been extended
608+
def _intercept_in_vitro_protein(nwbfile_object: pynwb.NWBFile, checks: Optional[list] = None) -> List[callable]:
609+
"""
610+
If the special 'protein' subject_id is specified, return a truncated list of checks to run.
611+
612+
This is a temporary method for allowing upload of certain in vitro data to DANDI and
613+
is expected to replaced in future versions.
614+
"""
615+
subject_related_check_names = [
616+
"check_subject_exists",
617+
"check_subject_id_exists",
618+
"check_subject_sex",
619+
"check_subject_species_exists",
620+
"check_subject_species_form",
621+
"check_subject_age",
622+
"check_subject_proper_age_range",
623+
]
624+
subject_related_dandi_requirements = [
625+
check.importance == Importance.CRITICAL for check in checks if check.__name__ in subject_related_check_names
626+
]
627+
628+
subject = getattr(nwbfile_object, "subject", None)
629+
if (
630+
any(subject_related_dandi_requirements)
631+
and subject is not None
632+
and getattr(subject, "subject_id", "").startswith("protein")
633+
):
634+
non_subject_checks = [check for check in checks if check.__name__ not in subject_related_check_names]
635+
return non_subject_checks
636+
return checks
637+
638+
607639
def inspect_nwbfile_object(
608640
nwbfile_object: pynwb.NWBFile,
609641
checks: Optional[list] = None,
@@ -651,7 +683,9 @@ def inspect_nwbfile_object(
651683
checks=checks, config=config, ignore=ignore, select=select, importance_threshold=importance_threshold
652684
)
653685

654-
for inspector_message in run_checks(nwbfile=nwbfile_object, checks=checks):
686+
subject_dependent_checks = _intercept_in_vitro_protein(nwbfile_object=nwbfile_object, checks=checks)
687+
688+
for inspector_message in run_checks(nwbfile=nwbfile_object, checks=subject_dependent_checks):
655689
yield inspector_message
656690

657691

tests/test_inspector.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import os
2-
import pytest
32
from shutil import rmtree
43
from tempfile import mkdtemp
54
from pathlib import Path
@@ -8,7 +7,7 @@
87

98
import numpy as np
109
from pynwb import NWBFile, NWBHDF5IO, TimeSeries
11-
from pynwb.file import TimeIntervals
10+
from pynwb.file import TimeIntervals, Subject
1211
from pynwb.behavior import SpatialSeries, Position
1312
from hdmf.common import DynamicTable
1413
from natsort import natsorted
@@ -22,7 +21,7 @@
2221
check_subject_exists,
2322
load_config,
2423
)
25-
from nwbinspector import inspect_all, inspect_nwbfile, available_checks
24+
from nwbinspector import inspect_all, inspect_nwbfile, inspect_nwbfile_object, available_checks
2625
from nwbinspector.register_checks import Severity, InspectorMessage, register_check
2726
from nwbinspector.tools import make_minimal_nwbfile
2827
from nwbinspector.utils import FilePathType
@@ -727,3 +726,17 @@ def test_check_unique_identifiers_fail(self):
727726
file_path=str(self.tempdir),
728727
)
729728
]
729+
730+
731+
def test_dandi_config_in_vitro_injection():
732+
"""Test that a subject_id starting with 'protein' excludes meaningless CRITICAL-elevated subject checks."""
733+
nwbfile = make_minimal_nwbfile()
734+
nwbfile.subject = Subject(
735+
subject_id="proteinCaMPARI3", description="A detailed description about the in vitro setup."
736+
)
737+
config = load_config(filepath_or_keyword="dandi")
738+
importance_threshold = "CRITICAL"
739+
messages = list(
740+
inspect_nwbfile_object(nwbfile_object=nwbfile, config=config, importance_threshold=importance_threshold)
741+
)
742+
assert messages == []

0 commit comments

Comments
 (0)