Contributing New Checks
This guide will walk you through the process of contributing a new check to NWBInspector.
Overview
NWBInspector checks are Python functions that examine NWB files for compliance with best practices. Each check is:
Focused on a specific aspect of NWB files
Decorated with
register_check()Returns either
None(pass) orInspectorMessage(fail)
Step-by-Step Guide
1. Propose Your Check
Before writing code:
Open a ‘New Check’ issue
Describe what the check will validate
Link to relevant best practices documentation if applicable. If proposing a new best practice, please describe in detail.
Wait for approval before proceeding
2. Choose the Right Location
Checks are organized by category in src/nwbinspector/checks/. Choose the appropriate file based on what you’re checking:
_nwbfile_metadata.py- GeneralNWBFilemetadata_nwb_containers.py- NWB container objects_time_series.py-TimeSeriesobjects_tables.py-DynamicTableobjects_behavior.py- Behavioral data_icephys.py- Intracellular electrophysiology_ecephys.py- Extracellular electrophysiology_ophys.py- Optical physiology_ogen.py- Optogenetics_image_series.py-ImageSeriesobjects_images.py-Imagesobjects_general.py- attributes of general neurodata types
3. Write Your Check
Here’s a template for a new check:
@register_check(
importance=Importance.BEST_PRACTICE_SUGGESTION, # Choose appropriate level
neurodata_type=NWBFile # Most general applicable type
)
def check_my_feature(nwbfile: NWBFile) -> Optional[InspectorMessage]:
"""One-line description of what this check validates."""
if problem_detected:
return InspectorMessage(
message="Clear description of the issue and how to fix it."
)
return None
Note
The function name for the check should always start with check_
4. Choose the Right Importance Level
Select from three levels (see Checks by Importance for examples):
Importance.CRITICAL: High likelihood of incorrect data that can’t be caught by PyNWB validationImportance.BEST_PRACTICE_VIOLATION: Major violation of Best PracticesImportance.BEST_PRACTICE_SUGGESTION: Minor violation or missing optional metadata
5. Write Tests
Add tests in the corresponding test file under tests/unit_tests/. Include both passing and failing cases:
def test_my_feature_pass():
# Test case where check should pass
assert check_my_feature(nwbfile=NWBFile(...)) is None
def test_my_feature_fail():
# Test case where check should fail
assert check_my_feature(nwbfile=make_minimal_nwbfile()) == InspectorMessage(
message="Expected message"
)
6. Add Check to the Public Interface
Add an import for your check from the appropriate module in
src/nwbinspector/checks/__init__.pyAdd your check to the
`__all__`list insrc/nwbinspector/checks/__init__.pyto indicate the check is part of the public interface.
7. Add Check to the Documentation
Add a link to your new check function in the relevant best practice section of the docs/best_practices folder.
If needed, add a new section and label for your check:
.. _best_practice_my_feature:
My Feature
~~~~~~~~~~
Description of the best practice.
Check function: :py:meth:`~nwbinspector.checks._tables.check_my_feature`
Note
If the best practice label in the .rst file ends with the same pattern as the check function name,
(e.g. .. _best_practice_my_feature: and check_my_feature), a link to the best practice documentation
will be automatically added to the function API documentation.
However, if the name of your check function does not match the name of your best practice section label (e.g. if a single best practices section has multiple check functions), you can include a link in the function docstring to link to the related best practice section.
def check_my_feature(nwbfile: NWBFile) -> Optional[InspectorMessage]:
"""
One-line description of what this check validates.
Best Practice: :ref:`best_practice_my_feature_unique_label`
"""
7. Best Practices for Check Implementation
Keep logic simple and focused
Use descriptive variable names
Add comments for complex logic
Reuse utility functions from Utils when possible
Make error messages clear and actionable
Include links to relevant documentation in docstrings
8. Submit Your PR
Create a new branch
Add your check and tests
Run the test suite
Submit a Pull Request
Respond to review feedback
Example Check
Here’s a complete example of a well-implemented check:
@register_check(
importance=Importance.BEST_PRACTICE_SUGGESTION,
neurodata_type=NWBFile
)
def check_experimenter(nwbfile: NWBFile) -> Optional[InspectorMessage]:
"""Check if an experimenter has been added for the session."""
if not nwbfile.experimenter:
return InspectorMessage(
message="Experimenter is missing. Add experimenter information to improve metadata completeness."
)
return None
For more examples, see the Check Functions documentation.
Common Pitfalls
Too Broad: Checks should validate one specific thing
Unclear Messages: Error messages should clearly explain the issue and how to fix it
Missing Tests: Always include both passing and failing test cases
Wrong Importance: Carefully consider the impact of the issue being checked
Redundant Checks: Ensure your check isn’t duplicating existing functionality
Need Help?
Review existing Check Functions for examples
Ask questions in your issue before starting implementation
Request review from maintainers early in the process