Skip to content

Add method to find objects of a given neurodata type#2189

Open
h-mayorquin wants to merge 3 commits into
devfrom
add_find_descendants_method
Open

Add method to find objects of a given neurodata type#2189
h-mayorquin wants to merge 3 commits into
devfrom
add_find_descendants_method

Conversation

@h-mayorquin
Copy link
Copy Markdown
Contributor

This PR tries to complete the work started on PR #1737. It implements a couple of the design points raised in the previous discussion:

  • The method is defined on NWBContainer rather than on NWBFile directly, so it works on any sub-container (ProcessingModule, LFP, etc.) and is correctly scoped to that container's subtree.
  • String-to-class resolution goes through pynwb.get_type_map(copy=False), the live process-wide TypeMap (available since Remove unnecessary calls to deepcopy(get_type_map) #2121), rather than self.io.manager.type_map; the previous approach required the container to have been read or written through an IO, captured a snapshot of the TypeMap at IO-construction time, and so failed on in-memory containers and missed extensions loaded later in the same process.

Fix #560

Checklist

  • Did you update CHANGELOG.md with your changes?
  • Have you checked our Contributing document?
  • Have you ensured the PR clearly describes the problem and the solution?
  • Is your contribution compliant with our coding style? This can be checked running ruff check . && codespell from the source directory.
  • Have you checked to ensure that there aren't other open Pull Requests for the same change?
  • Have you included the relevant issue number using "Fix #XXX" notation where XXX is the issue number? By including "Fix #XXX" you allow GitHub to close issue #XXX when the PR is merged.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.19%. Comparing base (9231882) to head (ee0b91c).

Additional details and impacted files
@@           Coverage Diff           @@
##              dev    #2189   +/-   ##
=======================================
  Coverage   95.18%   95.19%           
=======================================
  Files          30       30           
  Lines        2991     2997    +6     
  Branches      444      445    +1     
=======================================
+ Hits         2847     2853    +6     
  Misses         86       86           
  Partials       58       58           
Flag Coverage Δ
integration 72.93% <28.57%> (-0.12%) ⬇️
unit 85.61% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@h-mayorquin h-mayorquin marked this pull request as ready for review May 13, 2026 22:40
@oruebel
Copy link
Copy Markdown
Contributor

oruebel commented May 14, 2026

@h-mayorquin this looks like something we probably would want to add on Container in HDMF instead since this is generic functionality that is independent of NWB specifics

@h-mayorquin
Copy link
Copy Markdown
Contributor Author

@oruebel

The original PR supports matching both by class and by string (e.g. collect_descendants_of_type("ElectricalSeries")). For matching the strings we need the utility pynwb.get_type_map(). Naively moving this to hdmf would create a circular dependency, as hdmf.common.get_type_map() does not have all the mappings that pynwb.get_type_map() has (e.g. "ElectricalSeries").

We could support the basic matching with class only in hdmf and then a method here can use that functionality and add the string matching, concretely:

# hdmf (no nwb type map knowledge)
def collect_descendants_of_type(self, type_):
    return [obj for obj in self.all_children()
            if obj is not self and isinstance(obj, type_)]
# pynwb (add string resolution support)
def collect_descendants_of_type(self, neurodata_type):
    if isinstance(neurodata_type, str):
        neurodata_type = self._get_type_map().get_dt_container_cls(neurodata_type)
    return super().collect_descendants_of_type(neurodata_type)

One thing that I don't like is that the hdmf loses support for the pattern that @rly described (filtering objects whose Python class was auto-generated from a cached extension namespace at read time), and we have two slightly different functions in pynwb and hdmf which might be surprising and confusing. This compels me to ask: besides the logical place for a thing to be, what would be the concrete gain of having a reduced version on hdmf?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Programmatically find all the time series in any NWB file

2 participants