-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add read_nwb_method
for local paths in both hdf5 and zarr
#1994
base: dev
Are you sure you want to change the base?
Changes from 9 commits
54d39b7
f8ce558
a5ca2ef
d1064c0
36e4965
46f0d41
2518fc8
f95ffc5
042860f
33847a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,6 @@ | |
import matplotlib.pyplot as plt | ||
import numpy as np | ||
|
||
from pynwb import NWBHDF5IO | ||
|
||
#################### | ||
# We will access NWB data on the `DANDI Archive <https://gui.dandiarchive.org/>`_, | ||
|
@@ -103,14 +102,17 @@ | |
# read the data into a :py:class:`~pynwb.file.NWBFile` object. | ||
|
||
filepath = "sub-P11HMH_ses-20061101_ecephys+image.nwb" | ||
# Open the file in read mode "r", | ||
io = NWBHDF5IO(filepath, mode="r") | ||
nwbfile = io.read() | ||
from pynwb import read_nwb | ||
|
||
nwbfile = read_nwb(filepath) | ||
Comment on lines
+105
to
+107
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think once the simplified read_nwb with streaming is supported we may want to go through the other tutorials that use io.read() in read only mode and update those as well. |
||
nwbfile | ||
|
||
####################################### | ||
# :py:class:`~pynwb.NWBHDF5IO` can also be used as a context manager: | ||
# For more advanced use cases, the :py:class:~pynwb.NWBHDF5IO class provides additional functionality. | ||
# Below, we demonstrate how :py:class:~pynwb.NWBHDF5IO can be used as a context manager | ||
# to read data from an NWB file in a more controlled manner: | ||
|
||
from pynwb import NWBHDF5IO | ||
with NWBHDF5IO(filepath, mode="r") as io2: | ||
nwbfile2 = io2.read() | ||
|
||
|
@@ -291,4 +293,4 @@ | |
# ----------------------- | ||
# It is good practice, especially on Windows, to close any files that you have opened. | ||
|
||
io.close() | ||
nwbfile.get_read_io().close() |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -535,6 +535,71 @@ | |||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
return nwbfile | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@docval({'name': 'path', 'type': (str, Path), 'doc': 'the path to the nwbfile'}, | ||||||||||||||||||||||||||||||||
is_method=False) | ||||||||||||||||||||||||||||||||
def read_nwb(**kwargs): | ||||||||||||||||||||||||||||||||
"""Read an NWB file from a local path. | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
High-level interface for reading NWB files. Automatically handles both HDF5 | ||||||||||||||||||||||||||||||||
and Zarr formats. For advanced use cases (parallel I/O, custom namespaces), | ||||||||||||||||||||||||||||||||
use NWBHDF5IO or NWBZarrIO. | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Parameters | ||||||||||||||||||||||||||||||||
---------- | ||||||||||||||||||||||||||||||||
path : str or pathlib.Path | ||||||||||||||||||||||||||||||||
Path to the NWB file. Can be either a local filesystem path to an HDF5 (.nwb) | ||||||||||||||||||||||||||||||||
or Zarr (.zarr) file | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Returns | ||||||||||||||||||||||||||||||||
------- | ||||||||||||||||||||||||||||||||
pynwb.NWBFile | ||||||||||||||||||||||||||||||||
The loaded NWB file object. | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
See Also | ||||||||||||||||||||||||||||||||
-------- | ||||||||||||||||||||||||||||||||
pynwb.NWBHDF5IO : Core I/O class for HDF5 files with advanced options. | ||||||||||||||||||||||||||||||||
hdmf_zarr.nwb.NWBZarrIO : Core I/O class for Zarr files with advanced options. | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Notes | ||||||||||||||||||||||||||||||||
----- | ||||||||||||||||||||||||||||||||
This function uses the following defaults: | ||||||||||||||||||||||||||||||||
* Always opens in read-only mode | ||||||||||||||||||||||||||||||||
* Automatically loads namespaces | ||||||||||||||||||||||||||||||||
* Detects file format based on extension | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think in the current implementation other extensions will work since |
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Advanced features requiring direct use of IO classes include: | ||||||||||||||||||||||||||||||||
* Streaming data from s3 | ||||||||||||||||||||||||||||||||
* Custom namespace extensions | ||||||||||||||||||||||||||||||||
* Parallel I/O with MPI | ||||||||||||||||||||||||||||||||
* Custom build managers | ||||||||||||||||||||||||||||||||
* Write or append modes | ||||||||||||||||||||||||||||||||
* Pre-opened HDF5 file objects or Zarr stores | ||||||||||||||||||||||||||||||||
* Remote file access configuration | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
Examples | ||||||||||||||||||||||||||||||||
-------- | ||||||||||||||||||||||||||||||||
Read a local NWB file: | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
>>> from pynwb import read_nwb | ||||||||||||||||||||||||||||||||
>>> nwbfile = read_nwb("path/to/file.nwb") | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
path = popargs('path', kwargs) | ||||||||||||||||||||||||||||||||
backend_is_hdf5 = NWBHDF5IO.can_read(path=path) | ||||||||||||||||||||||||||||||||
if backend_is_hdf5: | ||||||||||||||||||||||||||||||||
return NWBHDF5IO.read_nwb(path=path) | ||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||
from hdmf_zarr import NWBZarrIO | ||||||||||||||||||||||||||||||||
backend_is_zarr = NWBZarrIO.can_read(path=path) | ||||||||||||||||||||||||||||||||
if backend_is_zarr: | ||||||||||||||||||||||||||||||||
return NWBZarrIO.read_nwb(path=path) | ||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||
raise ValueError(f"Unsupported backend for file: {path}") | ||||||||||||||||||||||||||||||||
Comment on lines
+590
to
+595
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I believe read_nwb will currently return an ImportError if the user provides an invalid path but does not have hdmf_zarr installed. Can you support this case? |
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
from . import io as __io # noqa: F401,E402 | ||||||||||||||||||||||||||||||||
from .core import NWBContainer, NWBData # noqa: F401,E402 | ||||||||||||||||||||||||||||||||
from .base import TimeSeries, ProcessingModule # noqa: F401,E402 | ||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from pathlib import Path | ||
import tempfile | ||
|
||
from pynwb import read_nwb | ||
from pynwb.testing.mock.file import mock_NWBFile | ||
from pynwb.testing import TestCase | ||
|
||
import unittest | ||
try: | ||
from hdmf_zarr import NWBZarrIO # noqa f401 | ||
HAVE_NWBZarrIO = True | ||
except ImportError: | ||
HAVE_NWBZarrIO = False | ||
|
||
|
||
class TestReadNWBMethod(TestCase): | ||
""" | ||
Test that H5DataIO functions correctly on round trip with the HDF5IO backend | ||
""" | ||
def setUp(self): | ||
self.nwbfile = mock_NWBFile() | ||
|
||
|
||
def test_read_nwb_hdf5(self): | ||
from pynwb import NWBHDF5IO | ||
|
||
with tempfile.TemporaryDirectory() as temp_dir: | ||
path = Path(temp_dir) / "test.nwb" | ||
with NWBHDF5IO(path, 'w') as io: | ||
io.write(self.nwbfile) | ||
|
||
read_nwbfile = read_nwb(path=path) | ||
self.assertContainerEqual(read_nwbfile, self.nwbfile) | ||
read_nwbfile.get_read_io().close() | ||
|
||
@unittest.skipIf(not HAVE_NWBZarrIO, "NWBZarrIO library not available") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add tests for
|
||
def test_read_zarr(self): | ||
# from pynwb import NWBZarrIO | ||
from hdmf_zarr import NWBZarrIO | ||
|
||
with tempfile.TemporaryDirectory() as temp_dir: | ||
path = Path(temp_dir) / "test.nwb" | ||
with NWBZarrIO(path, 'w') as io: | ||
io.write(self.nwbfile) | ||
|
||
read_nwbfile = read_nwb(path=path) | ||
self.assertContainerEqual(read_nwbfile, self.nwbfile) | ||
read_nwbfile.get_read_io().close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These updates were indented to indicate schema 2.8.0 related changes