Skip to content
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

can_read method for NWBHDF5IO respects NWB version #1703

Merged
merged 8 commits into from
Oct 4, 2023
Merged
Changes from 1 commit
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
Next Next commit
can_read method for NWBHDF5IO respects NWB version
bendichter committed Jun 19, 2023
commit 022d16645e8d2124165687c912c17f5083b681b8
49 changes: 32 additions & 17 deletions src/pynwb/__init__.py
Original file line number Diff line number Diff line change
@@ -147,6 +147,25 @@ def _dec(cls):
else:
_dec(container_cls)

def get_nwbfile_version(h5py_file):
# Get the version string for the NWB file
try:
nwb_version_string = h5py_file.attrs['nwb_version']
# KeyError occurs when the file is empty (e.g., when creating a new file nothing has been written)
# or when the HDF5 file is not a valid NWB file
except KeyError:
return None, None
# Other system may have written nwb_version as a fixed-length string, resulting in a numpy.bytes_ object
# on read, rather than a variable-length string. To address this, decode the bytes if necessary.
if not isinstance(nwb_version_string, str):
nwb_version_string = nwb_version_string.decode()

# Parse the version string
nwb_version_parts = nwb_version_string.replace("-", ".").replace("_", ".").split(".")
nwb_version = tuple([int(i) if i.isnumeric() else i
for i in nwb_version_parts])
return nwb_version_string, nwb_version


# a function to register an object mapper for a container class
@docval({"name": "container_cls", "type": type,
@@ -201,6 +220,18 @@ def get_sum(self, a, b):

class NWBHDF5IO(_HDF5IO):

@staticmethod
def can_read(path):
"""Determine whether a given path is readable by this class"""
if not os.path.isfile(path): # path is file that exists
return False
try:
with h5py.File(path, "r") as file: # path is HDF5 file
return get_nwbfile_version(file)[1][0] >= 2 # Major version of NWB >= 2
except IOError:
return False


@docval({'name': 'path', 'type': (str, Path), 'doc': 'the path to the HDF5 file', 'default': None},
{'name': 'mode', 'type': str,
'doc': 'the mode to open the HDF5 file with, one of ("w", "r", "r+", "a", "w-", "x")',
@@ -259,23 +290,7 @@ def nwb_version(self):
and strings, e.g., (2, 5, 1, beta). (None, None) will be returned if the nwb_version
is missing, e.g., in the case when no data has been written to the file yet.
"""
# Get the version string for the NWB file
try:
nwb_version_string = self._file.attrs['nwb_version']
# KeyError occurs when the file is empty (e.g., when creating a new file nothing has been written)
# or when the HDF5 file is not a valid NWB file
except KeyError:
return None, None
# Other system may have written nwb_version as a fixed-length string, resulting in a numpy.bytes_ object
# on read, rather than a variable-length string. To address this, decode the bytes if necessary.
if not isinstance(nwb_version_string, str):
nwb_version_string = nwb_version_string.decode()

# Parse the version string
nwb_version_parts = nwb_version_string.replace("-", ".").replace("_", ".").split(".")
nwb_version = tuple([int(i) if i.isnumeric() else i
for i in nwb_version_parts])
return nwb_version_string, nwb_version
get_nwbfile_version(self._file)

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