Skip to content

Commit 2aceed0

Browse files
bendichterrly
andauthored
can_read method for NWBHDF5IO respects NWB version (#1703)
Co-authored-by: Ryan Ly <[email protected]>
1 parent 734a6c4 commit 2aceed0

File tree

2 files changed

+45
-17
lines changed

2 files changed

+45
-17
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# PyNWB Changelog
22

3+
## PyNWB 2.6.0 (Upcoming)
4+
5+
### Enhancements and minor changes
6+
- Add `NWBHDF5IO.can_read()`. @bendichter [#1703](https://github.com/NeurodataWithoutBorders/pynwb/pull/1703)
7+
- Add `pynwb.get_nwbfile_version()`. @bendichter [#1703](https://github.com/NeurodataWithoutBorders/pynwb/pull/1703)
8+
39
## PyNWB 2.5.0 (August 18, 2023)
410

511
### Enhancements and minor changes

src/pynwb/__init__.py

+39-17
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,33 @@ def _dec(cls):
148148
_dec(container_cls)
149149

150150

151+
def get_nwbfile_version(h5py_file: h5py.File):
152+
"""
153+
Get the NWB version of the file if it is an NWB file.
154+
:returns: Tuple consisting of: 1) the original version string as stored in the file and
155+
2) a tuple with the parsed components of the version string, consisting of integers
156+
and strings, e.g., (2, 5, 1, beta). (None, None) will be returned if the file is not a valid NWB file
157+
or the nwb_version is missing, e.g., in the case when no data has been written to the file yet.
158+
"""
159+
# Get the version string for the NWB file
160+
try:
161+
nwb_version_string = h5py_file.attrs['nwb_version']
162+
# KeyError occurs when the file is empty (e.g., when creating a new file nothing has been written)
163+
# or when the HDF5 file is not a valid NWB file
164+
except KeyError:
165+
return None, None
166+
# Other system may have written nwb_version as a fixed-length string, resulting in a numpy.bytes_ object
167+
# on read, rather than a variable-length string. To address this, decode the bytes if necessary.
168+
if not isinstance(nwb_version_string, str):
169+
nwb_version_string = nwb_version_string.decode()
170+
171+
# Parse the version string
172+
nwb_version_parts = nwb_version_string.replace("-", ".").replace("_", ".").split(".")
173+
nwb_version = tuple([int(i) if i.isnumeric() else i
174+
for i in nwb_version_parts])
175+
return nwb_version_string, nwb_version
176+
177+
151178
# a function to register an object mapper for a container class
152179
@docval({"name": "container_cls", "type": type,
153180
"doc": "the Container class for which the given ObjectMapper class gets used"},
@@ -201,6 +228,17 @@ def get_sum(self, a, b):
201228

202229
class NWBHDF5IO(_HDF5IO):
203230

231+
@staticmethod
232+
def can_read(path: str):
233+
"""Determine whether a given path is readable by this class"""
234+
if not os.path.isfile(path): # path is file that exists
235+
return False
236+
try:
237+
with h5py.File(path, "r") as file: # path is HDF5 file
238+
return get_nwbfile_version(file)[1][0] >= 2 # Major version of NWB >= 2
239+
except IOError:
240+
return False
241+
204242
@docval({'name': 'path', 'type': (str, Path), 'doc': 'the path to the HDF5 file', 'default': None},
205243
{'name': 'mode', 'type': str,
206244
'doc': 'the mode to open the HDF5 file with, one of ("w", "r", "r+", "a", "w-", "x")',
@@ -263,23 +301,7 @@ def nwb_version(self):
263301
and strings, e.g., (2, 5, 1, beta). (None, None) will be returned if the nwb_version
264302
is missing, e.g., in the case when no data has been written to the file yet.
265303
"""
266-
# Get the version string for the NWB file
267-
try:
268-
nwb_version_string = self._file.attrs['nwb_version']
269-
# KeyError occurs when the file is empty (e.g., when creating a new file nothing has been written)
270-
# or when the HDF5 file is not a valid NWB file
271-
except KeyError:
272-
return None, None
273-
# Other system may have written nwb_version as a fixed-length string, resulting in a numpy.bytes_ object
274-
# on read, rather than a variable-length string. To address this, decode the bytes if necessary.
275-
if not isinstance(nwb_version_string, str):
276-
nwb_version_string = nwb_version_string.decode()
277-
278-
# Parse the version string
279-
nwb_version_parts = nwb_version_string.replace("-", ".").replace("_", ".").split(".")
280-
nwb_version = tuple([int(i) if i.isnumeric() else i
281-
for i in nwb_version_parts])
282-
return nwb_version_string, nwb_version
304+
return get_nwbfile_version(self._file)
283305

284306
@docval(*get_docval(_HDF5IO.read),
285307
{'name': 'skip_version_check', 'type': bool, 'doc': 'skip checking of NWB version', 'default': False})

0 commit comments

Comments
 (0)