From 4545d716e0c17e45328956f54b6ec8995dfd25c3 Mon Sep 17 00:00:00 2001 From: Matthew Avaylon Date: Tue, 11 Jul 2023 11:18:47 -0700 Subject: [PATCH] NWBHDF5IO ER and ER_Manager (#1684) --- CHANGELOG.md | 1 + requirements-min.txt | 4 ++-- requirements.txt | 2 +- setup.py | 2 +- src/pynwb/__init__.py | 16 ++++++++++------ src/pynwb/file.py | 3 ++- src/pynwb/resources.py | 10 ++++++++++ tests/unit/test_resources.py | 11 +++++++++++ 8 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/pynwb/resources.py create mode 100644 tests/unit/test_resources.py diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d474a73..3a84fc818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## PyNWB 2.4.0 (Upcoming) ### Enhancements and minor changes +- Add support for `ExternalResources`. @mavaylon1 [#1684](https://github.com/NeurodataWithoutBorders/pynwb/pull/1684) - Update links for making a release. @mavaylon1 [#1720](https://github.com/NeurodataWithoutBorders/pynwb/pull/1720) ## PyNWB 2.3.3 (June 26, 2023) diff --git a/requirements-min.txt b/requirements-min.txt index 46a79dce0..52f891905 100644 --- a/requirements-min.txt +++ b/requirements-min.txt @@ -1,7 +1,7 @@ # minimum versions of package dependencies for installing PyNWB h5py==2.10 # support for selection of datasets with list of indices added in 2.10 -hdmf==3.5.4 -numpy==1.16 +hdmf==3.7.0 +numpy==1.18 pandas==1.1.5 python-dateutil==2.7.3 setuptools diff --git a/requirements.txt b/requirements.txt index 81eee86c3..7313addc4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # pinned dependencies to reproduce an entire development environment to use PyNWB h5py==3.8.0 -hdmf==3.5.4 +hdmf==3.7.0 numpy==1.24.2 pandas==2.0.0 python-dateutil==2.8.2 diff --git a/setup.py b/setup.py index baf585e7c..46334a20d 100755 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ reqs = [ 'h5py>=2.10', - 'hdmf>=3.5.4', + 'hdmf>=3.7.0', 'numpy>=1.16', 'pandas>=1.1.5', 'python-dateutil>=2.7.3', diff --git a/src/pynwb/__init__.py b/src/pynwb/__init__.py index 023cda237..181079970 100644 --- a/src/pynwb/__init__.py +++ b/src/pynwb/__init__.py @@ -215,10 +215,13 @@ class NWBHDF5IO(_HDF5IO): {'name': 'file', 'type': [h5py.File, 'S3File'], 'doc': 'a pre-existing h5py.File object', 'default': None}, {'name': 'comm', 'type': "Intracomm", 'doc': 'the MPI communicator to use for parallel I/O', 'default': None}, - {'name': 'driver', 'type': str, 'doc': 'driver for h5py to use when opening HDF5 file', 'default': None}) + {'name': 'driver', 'type': str, 'doc': 'driver for h5py to use when opening HDF5 file', 'default': None}, + {'name': 'external_resources_path', 'type': str, 'doc': 'The path to the ExternalResources', + 'default': None},) def __init__(self, **kwargs): - path, mode, manager, extensions, load_namespaces, file_obj, comm, driver =\ - popargs('path', 'mode', 'manager', 'extensions', 'load_namespaces', 'file', 'comm', 'driver', kwargs) + path, mode, manager, extensions, load_namespaces, file_obj, comm, driver, external_resources_path =\ + popargs('path', 'mode', 'manager', 'extensions', 'load_namespaces', + 'file', 'comm', 'driver', 'external_resources_path', kwargs) # Define the BuildManager to use if load_namespaces: if manager is not None: @@ -247,7 +250,8 @@ def __init__(self, **kwargs): elif manager is None: manager = get_manager() # Open the file - super().__init__(path, manager=manager, mode=mode, file=file_obj, comm=comm, driver=driver) + super().__init__(path, manager=manager, mode=mode, file=file_obj, comm=comm, + driver=driver, external_resources_path=external_resources_path) @property def nwb_version(self): @@ -297,7 +301,8 @@ def read(self, **kwargs): raise TypeError("NWB version %s not supported. PyNWB supports NWB files version 2 and above." % str(file_version_str)) # read the file - return super().read(**kwargs) + file = super().read(**kwargs) + return file @docval({'name': 'src_io', 'type': HDMFIO, 'doc': 'the HDMFIO object (such as NWBHDF5IO) that was used to read the data to export'}, @@ -349,7 +354,6 @@ def export(self, **kwargs): from .core import NWBContainer, NWBData # noqa: F401,E402 from .base import TimeSeries, ProcessingModule # noqa: F401,E402 from .file import NWBFile # noqa: F401,E402 - from . import behavior # noqa: F401,E402 from . import device # noqa: F401,E402 from . import ecephys # noqa: F401,E402 diff --git a/src/pynwb/file.py b/src/pynwb/file.py index 31b2d8e1e..b03141b7f 100644 --- a/src/pynwb/file.py +++ b/src/pynwb/file.py @@ -8,6 +8,7 @@ import pandas as pd from hdmf.common import DynamicTableRegion, DynamicTable +from hdmf.container import ExternalResourcesManager from hdmf.utils import docval, getargs, get_docval, popargs, popargs_to_dict, AllowPositional from . import register_class, CORE_NAMESPACE @@ -149,7 +150,7 @@ def __init__(self, **kwargs): @register_class('NWBFile', CORE_NAMESPACE) -class NWBFile(MultiContainerInterface): +class NWBFile(MultiContainerInterface, ExternalResourcesManager): """ A representation of an NWB file. """ diff --git a/src/pynwb/resources.py b/src/pynwb/resources.py new file mode 100644 index 000000000..bfb8a6ba2 --- /dev/null +++ b/src/pynwb/resources.py @@ -0,0 +1,10 @@ +from hdmf.common import ExternalResources as hdmf_ExternalResources +from . import get_type_map as tm +from hdmf.utils import docval, get_docval + + +class ExternalResources(hdmf_ExternalResources): + @docval(*get_docval(hdmf_ExternalResources.__init__)) + def __init__(self, **kwargs): + kwargs['type_map'] = tm() + super().__init__(**kwargs) diff --git a/tests/unit/test_resources.py b/tests/unit/test_resources.py new file mode 100644 index 000000000..cfb598b7b --- /dev/null +++ b/tests/unit/test_resources.py @@ -0,0 +1,11 @@ +from pynwb.resources import ExternalResources +from pynwb.testing import TestCase + + +class TestNWBContainer(TestCase): + def test_constructor(self): + """ + Test constructor + """ + er = ExternalResources() + self.assertIsInstance(er, ExternalResources)