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

Add methods to find objects of a given neurodata type / pynwb class #1737

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
29 changes: 29 additions & 0 deletions src/pynwb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,35 @@ def export(self, **kwargs):
kwargs['container'] = nwbfile
super().export(**kwargs)

@docval({'name': 'neurodata_type', 'type': str, 'doc': 'The neurodata type to search for.'},
{'name': 'namespace', 'type': str, 'doc': 'The namespace of the neurodata type to search for.'},)
def get_neurodata_type_objs(self, neurodata_type: str, namespace: str):
"""Return all PyNWB objects in the file that have a neurodata type from a namespace.

This works regardless of whether the extension was imported earlier in the python execution.

This method is useful for getting neurodata type objects from cached extensions where you
do not have easy access to a python class to pass to `NWBFile.find_all_of_class`.

All objects that are instances of the class associated with the given neurodata_type in the
given namespace will be returned. This includes objects that are instances of a subclass.
rly marked this conversation as resolved.
Show resolved Hide resolved

For example, if an extension defines a new neurodata type OnePhotonSeries that extends
ImageSeries, then `get_neurodata_type_objects_in_file(io, "ImageSeries", "core")` will
include all OnePhotonSeries objects.

.. code-block:: python

from pynwb import NWBHDF5IO
with NWBHDF5IO(filepath, mode="r", load_namespaces=True) as io:
obj_list = io.get_neurodata_type_objs("Subject", "core")

"""
pynwb_cls = self.manager.type_map.get_dt_container_cls(neurodata_type, namespace)

read_nwbfile = self.read()
return read_nwbfile.find_all_of_class(pynwb_cls)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify what use-case this function addresses that NWBFile.find_all_of_class does not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment in the docstring. It says: This method is useful for getting neurodata type objects from cached extensions where you do not have easy access to a python class to pass to NWBFile.find_all_of_class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. But it seems a bit strange that this functionality is in two different places. Also, with this we would need to duplicate this also for Zarr. Instead, I'm wondering whether find_all_of_class can be modified to do both, something like:

@docval({'name': 'neurodata_types', 'type': (type, str), 'doc': 'The PyNWB container class to search for instances of or the string with the name of the neurodata_type'},)
def find_all(self, neurodata_type):
     if isinstance(neurodata_type, str):
         pynwb_cls = self.io.manager.type_map.get_dt_container_cls(neurodata_type, namespace)
     else:
        pynwb_cls = neurodata_type
     ret = [obj for obj in self.objects.values() if isinstance(obj, pynwb_class)]
     return ret

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that works too. I'll update it



from . import io as __io # noqa: F401,E402
from .core import NWBContainer, NWBData # noqa: F401,E402
Expand Down
15 changes: 15 additions & 0 deletions src/pynwb/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,21 @@ def objects(self):
self.all_children()
return self.__obj

@docval({'name': 'pynwb_class', 'type': type, 'doc': 'The PyNWB class to search for instances of.'},)
def find_all_of_class(self, pynwb_class: type):
"""Return all PyNWB objects in the file that are instances of the pynwb_class class.

This includes objects that are instances of a subclass of the class.

.. code-block:: python

from pynwb import ImageSeries
obj_list = get_neurodata_type_objects(nwbfile, ImageSeries)

"""
ret = [obj for obj in self.objects.values() if isinstance(obj, pynwb_class)]
return ret

@property
def modules(self):
warn("NWBFile.modules has been replaced by NWBFile.processing.", DeprecationWarning)
Expand Down