Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/all_os_versions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["ubuntu-latest", "macos-latest", "windows-latest"]
1 change: 1 addition & 0 deletions .github/workflows/all_python_versions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["3.10", "3.13"]
64 changes: 53 additions & 11 deletions .github/workflows/dailies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,77 @@ on:

jobs:

load_python_and_os_versions:
runs-on: ubuntu-latest
outputs:
ALL_PYTHON_VERSIONS: ${{ steps.load_python_versions.outputs.python_versions }}
ALL_OS_VERSIONS: ${{ steps.load_os_versions.outputs.os_versions }}
steps:
- uses: actions/checkout@v4
- id: load_python_versions
run: echo "python_versions=$(cat ./.github/workflows/all_python_versions.txt)" >> "$GITHUB_OUTPUT"
- id: load_os_versions
run: echo "os_versions=$(cat ./.github/workflows/all_os_versions.txt)" >> "$GITHUB_OUTPUT"

run-daily-tests:
needs: load_python_and_os_versions
uses: neurodatawithoutborders/nwbinspector/.github/workflows/testing.yml@dev
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
python-versions: ${{ needs.load_python_and_os_versions.outputs.ALL_PYTHON_VERSIONS }}
os-versions: ${{ needs.load_python_and_os_versions.outputs.ALL_OS_VERSIONS }}

run-daily-doc-link-checks:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/doc-link-checks.yml@dev

test-dandi-latest:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/dandi-release.yml@dev

test-dandi-dev:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/dandi-dev.yml@dev
notify-tests-failure:
runs-on: ubuntu-latest
needs: [run-daily-tests]
if: ${{ always() && needs.run-daily-tests.result == 'failure' }}
steps:
- uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: NWB Inspector Daily Failure - tests
to: rly@lbl.gov
from: NWB Inspector
body: "The daily test workflow failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dailies.yml"

test-dandi-dev-live:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/dandi-dev-live-services.yml@dev
notify-doc-link-checks-failure:
runs-on: ubuntu-latest
needs: [run-daily-doc-link-checks]
if: ${{ always() && needs.run-daily-doc-link-checks.result == 'failure' }}
steps:
- uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: NWB Inspector Daily Failure - doc link checks
to: rly@lbl.gov
from: NWB Inspector
body: "The daily documentation link check failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dailies.yml"

notify:
notify-dandi-latest-failure:
runs-on: ubuntu-latest
needs: [run-daily-tests, run-daily-doc-link-checks, test-dandi-latest, test-dandi-dev, test-dandi-dev-live]
if: failure()
needs: [test-dandi-latest]
if: ${{ always() && needs.test-dandi-latest.result == 'failure' }}
steps:
- uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465 # TSL
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: NWB Inspector Daily Failure
to: smprince@lbl.gov, rly@lbl.gov
subject: NWB Inspector Daily Failure - DANDI latest release
to: rly@lbl.gov
from: NWB Inspector
body: "The daily workflow for the NWB Inspector failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dailies.yml"
body: "The daily test against the latest released DANDI failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dailies.yml"
32 changes: 16 additions & 16 deletions .github/workflows/deploy-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ concurrency:


jobs:
load_python_and_os_versions:
runs-on: ubuntu-latest
outputs:
ALL_PYTHON_VERSIONS: ${{ steps.load_python_versions.outputs.python_versions }}
ALL_OS_VERSIONS: ${{ steps.load_os_versions.outputs.os_versions }}
steps:
- uses: actions/checkout@v4
- id: load_python_versions
run: echo "python_versions=$(cat ./.github/workflows/all_python_versions.txt)" >> "$GITHUB_OUTPUT"
- id: load_os_versions
run: echo "os_versions=$(cat ./.github/workflows/all_os_versions.txt)" >> "$GITHUB_OUTPUT"

assess-file-changes:
uses: ./.github/workflows/assess-file-changes.yml

Expand All @@ -29,11 +41,14 @@ jobs:
uses: ./.github/workflows/doc-link-checks.yml

run-tests:
needs: assess-file-changes
needs: [assess-file-changes, load_python_and_os_versions]
if: ${{ needs.assess-file-changes.outputs.SOURCE_CHANGED == 'true' }}
uses: ./.github/workflows/testing.yml
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
python-versions: ${{ needs.load_python_and_os_versions.outputs.ALL_PYTHON_VERSIONS }}
os-versions: ${{ needs.load_python_and_os_versions.outputs.ALL_OS_VERSIONS }}

run-streaming-tests:
needs: assess-file-changes
Expand All @@ -49,26 +64,11 @@ jobs:
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

run-dev-gallery:
needs: assess-file-changes
if: ${{ needs.assess-file-changes.outputs.SOURCE_CHANGED == 'true' }}
uses: ./.github/workflows/dev-gallery.yml

test-dandi-latest:
needs: assess-file-changes
if: ${{ needs.assess-file-changes.outputs.SOURCE_CHANGED == 'true' }}
uses: ./.github/workflows/dandi-release.yml

test-dandi-dev:
needs: assess-file-changes
if: ${{ needs.assess-file-changes.outputs.SOURCE_CHANGED == 'true' }}
uses: ./.github/workflows/dandi-dev.yml

test-dandi-dev-live:
needs: assess-file-changes
if: ${{ needs.assess-file-changes.outputs.SOURCE_CHANGED == 'true' }}
uses: ./.github/workflows/dandi-dev-live-services.yml

check-final-status:
name: All tests passing
if: always()
Expand Down
65 changes: 65 additions & 0 deletions .github/workflows/dev-dailies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Daily dev workflows

on:
workflow_dispatch:
schedule:
- cron: "0 14 * * *" # Daily at 10am EST

jobs:

test-pynwb-dev:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/pynwb-dev-tests.yml@dev

test-dandi-dev:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/dandi-dev.yml@dev

test-dandi-dev-live:
uses: neurodatawithoutborders/nwbinspector/.github/workflows/dandi-dev-live-services.yml@dev

notify-pynwb-dev-failure:
runs-on: ubuntu-latest
needs: [test-pynwb-dev]
if: ${{ always() && needs.test-pynwb-dev.result == 'failure' }}
steps:
- uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: NWB Inspector Daily Failure - pynwb dev branch
to: rly@lbl.gov
from: NWB Inspector
body: "The daily test against the pynwb dev branch failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dev-dailies.yml"

notify-dandi-dev-failure:
runs-on: ubuntu-latest
needs: [test-dandi-dev]
if: ${{ always() && needs.test-dandi-dev.result == 'failure' }}
steps:
- uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: NWB Inspector Daily Failure - DANDI dev branch (offline)
to: rly@lbl.gov
from: NWB Inspector
body: "The daily test against the DANDI dev branch (offline) failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dev-dailies.yml"

notify-dandi-dev-live-failure:
runs-on: ubuntu-latest
needs: [test-dandi-dev-live]
if: ${{ always() && needs.test-dandi-dev-live.result == 'failure' }}
steps:
- uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: NWB Inspector Daily Failure - DANDI dev branch (live services)
to: rly@lbl.gov
from: NWB Inspector
body: "The daily test against the DANDI dev branch with live services failed: please check status at https://github.com/NeurodataWithoutBorders/nwbinspector/actions/workflows/dev-dailies.yml"
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: Development Version Gallery
name: Testing against pynwb dev branch
on: workflow_call

env:
TESTING_FILES_FOLDER_PATH: ./204919/testing_files/

jobs:
build-and-test:
name: Testing against dev PyNWB version
name: Testing nwbinspector against pynwb dev branch
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down
29 changes: 14 additions & 15 deletions .github/workflows/read-nwbfile-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,34 @@ jobs:
name: Streaming tests using ${{ matrix.os }} with ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash -l {0} # necessary for conda
run:
shell: bash -l {0} # necessary for conda activation, including on Windows
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "windows-latest"] # TODO: update mac and streaming methods
python-version: ["3.10", "3.13"]
steps:
- uses: conda-incubator/setup-miniconda@v3
- uses: actions/checkout@v4
- run: git fetch --prune --unshallow --tags

# Use the conda-forge h5py because the PyPI wheel does not bundle the ROS3 driver.
# `activate-environment` + `auto-activate-base: false` are what make the activation
# propagate across steps on Windows; without them, h5py ends up installed into a base
# environment that subsequent `pytest` invocations cannot see.
- name: Set up Conda
uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
activate-environment: ros3
environment-file: environment-ros3.yml
python-version: ${{ matrix.python-version }}
channels: conda-forge
- uses: actions/checkout@v4
- run: git fetch --prune --unshallow --tags

- name: Install pytest
run: |
pip install pytest
pip install pytest-cov
auto-activate-base: false

- name: Install package
run: pip install ".[dandi,zarr]" s3fs

- name: Uninstall h5py
run: pip uninstall -y h5py
- name: Install ROS3
run: conda install -c conda-forge h5py

- name: Run pytest on streaming-based read_nwbfile tests
run: pytest -rsx --cov=nwbinspector --cov-report xml:./coverage.xml tests/read_nwbfile_streaming_tests.py

Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
name: Testing
on:
workflow_call:
inputs:
python-versions:
description: 'List of Python versions to use in matrix, as JSON string'
required: true
type: string
os-versions:
description: 'List of OS versions to use in matrix, as JSON string'
required: true
type: string
secrets:
CODECOV_TOKEN:
required: true
Expand All @@ -12,8 +21,8 @@ jobs:
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.10", "3.13"]
os: ${{ fromJson(inputs.os-versions) }}
python-version: ${{ fromJson(inputs.python-versions) }}
env:
TESTING_FILES_FOLDER_PATH: ./204919/testing_files/
steps:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

### Improvements
* Made `hdmf-zarr` an optional dependency to restore pip-installability when `numcodecs` wheels are unavailable. Install with `pip install nwbinspector[zarr]` to enable Zarr-backed NWB file inspection. The local-file read path now delegates to `pynwb.read_nwb`, which produces a clear install hint when a Zarr file is encountered without the `[zarr]` extra. [#698](https://github.com/NeurodataWithoutBorders/nwbinspector/issues/698)
* Reorganized CI so upstream-dev test failures no longer gate PRs. Dev-branch jobs (`test-pynwb-dev`, `test-dandi-dev`, `test-dandi-dev-live`) moved from `deploy-tests.yml` into a new `dev-dailies.yml` scheduled workflow. Also added per-workflow failure emails, centralized the `testing.yml` Python and OS matrices into shared text files, renamed `dev-gallery.yml` to `pynwb-dev-tests.yml`, and rewrote `read-nwbfile-tests.yml` to use a named conda environment (`environment-ros3.yml`) so the ROS3-enabled h5py from conda-forge activates correctly on Windows runners. [#700](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/700)

### Fixes
* Fixed ROS3 streaming in `read_nwbfile` after h5py began enforcing an explicit `aws_region` for the ROS3 driver. Added a `backend_kwargs` keyword-only parameter to `read_nwbfile` that forwards arbitrary kwargs to the underlying `NWBHDF5IO` constructor on the streaming paths (`fsspec`, `ros3`); ROS3 callers now pass `backend_kwargs={"aws_region": "us-east-1"}`. The generic escape hatch avoids having to surface each new upstream kwarg individually. [#700](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/700)
* Deprecated `read_nwbfile_and_io`; it will be removed after 2026-11-13. Use `read_nwbfile` instead; the IO object is accessible from the returned NWBFile via `nwbfile.get_read_io()`. [#700](https://github.com/NeurodataWithoutBorders/nwbinspector/pull/700)

# v0.7.1 (March 26, 2026)

Expand Down
17 changes: 17 additions & 0 deletions environment-ros3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Conda environment for ROS3 streaming tests.
#
# h5py from conda-forge ships compiled with the ROS3 virtual file driver enabled,
# which the PyPI wheels still do not (see https://github.com/h5py/h5py/issues/1884).
# This file is consumed by `.github/workflows/read-nwbfile-tests.yml` via
# `setup-miniconda`'s `environment-file` input, following the same pattern PyNWB uses
# to keep ROS3 tests green on Windows.

name: ros3
channels:
- conda-forge
dependencies:
- h5py
- pytest
- pytest-cov
- fsspec
- pip
4 changes: 2 additions & 2 deletions src/nwbinspector/_nwb_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from ._registration import Importance, InspectorMessage, available_checks
from .tools._read_nwbfile import (
_MissingHdmfZarrError,
_read_nwbfile_and_io,
read_nwbfile,
read_nwbfile_and_io,
)
from .utils import (
OptionalListOfStrings,
Expand Down Expand Up @@ -268,7 +268,7 @@ def inspect_nwbfile(

io = None
try:
in_memory_nwbfile, io = read_nwbfile_and_io(nwbfile_path=nwbfile_path)
in_memory_nwbfile, io = _read_nwbfile_and_io(nwbfile_path=nwbfile_path)

if not skip_validate:
validation_result = pynwb.validate(path=nwbfile_path)
Expand Down
Loading
Loading