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

extractor_dict_iterator for solving path detection in object kwargs #3089

Merged
merged 9 commits into from
Jun 28, 2024

Conversation

h-mayorquin
Copy link
Collaborator

@h-mayorquin h-mayorquin commented Jun 26, 2024

Extractor dicts (outputs of BaseExtractor.to_dict()) are nested structures where some arguments are paths.

For solving the problem in #3013 we need a way of filtering by the arguments that correspond to real paths (e.g. Path(argument).exists() is True) and only modify those.

The current approach is to use the recursive_path_modifier:
https://github.com/alejoe91/spikeinterface/blob/fa2ca6d7c804fc8ab3df93dbd463d9576bc7723b/src/spikeinterface/core/core_tools.py#L186

I guess at the beginning the purpose of the function was both iterating overt the dict and also modifying the values.
But then, some other functions appeared like get_path_list that use recursive_path_modifier to iterate over the extractor and accumulate path-like values.

This PR creates two functions that can accomplish the same as recursive_path_modifier but are decoupled:

  1. First, it introduces extractor_dict_iterator that generates an iterator over all elements with three attributes: value, name and access path.
  2. Second, a new set_value_in_extractor_dict function that uses the access path of the elements from the iterator to modify the value is also introduced.

With this logic, functions like find_recording_folders that only use the first part can avoid the part of recursive_path_modifier that modifies the values. Avoiding computational waste and simplifying intent. Moreover,, the problem in #3014 of having to check for path existence before or after a modification can be easily stated as a single line where elements are filtered instead of modifying the logic of recursive_path_modifier. In general it enables working with extractor dicts in the folowing way:

  1. Collect items from the extractor dict
  2. Filter to select some of them
  3. Modify them

Note that this does not even need to be about paths. Any type of filter, reduce or concistency check and modification can be implemented with this.

I also modified the tests of make_relative_paths and make_absolute_paths to work on real paths so we can directly test the type of problem causes #3013

@h-mayorquin h-mayorquin self-assigned this Jun 26, 2024
@h-mayorquin h-mayorquin requested a review from alejoe91 June 26, 2024 23:03
@h-mayorquin h-mayorquin added bug Something isn't working core Changes to core module labels Jun 26, 2024
Copy link
Member

@alejoe91 alejoe91 left a comment

Choose a reason for hiding this comment

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

@h-mayorquin I love this! just some renaming suggestions

src/spikeinterface/core/core_tools.py Outdated Show resolved Hide resolved
src/spikeinterface/core/core_tools.py Outdated Show resolved Hide resolved
src/spikeinterface/core/core_tools.py Outdated Show resolved Hide resolved
src/spikeinterface/core/core_tools.py Outdated Show resolved Hide resolved
src/spikeinterface/core/core_tools.py Outdated Show resolved Hide resolved
@alejoe91
Copy link
Member

@h-mayorquin this should cloe #3014 right?

@alejoe91 alejoe91 added this to the 0.101.0 milestone Jun 27, 2024
@h-mayorquin
Copy link
Collaborator Author

@alejoe91 did the correction and yes, this should close #3041

@alejoe91
Copy link
Member

@h-mayorquin can you make the previous test function in test_core_tools (test_path_utils_functions) also to use pytest.skip?

@h-mayorquin
Copy link
Collaborator Author

Yes, done.

@alejoe91
Copy link
Member

This looks good to me. Much much cleaner than the old presentation!

@samuelgarcia what do you think?

@h-mayorquin h-mayorquin marked this pull request as ready for review June 27, 2024 16:20
@samuelgarcia
Copy link
Member

I guess at the beginning the purpose of the function was both iterating overt the dict and also modifying the values. But then, some other functions appeared like get_path_list that use recursive_path_modifier to iterate over the extractor and accumulate path-like values.

Excellent guess and analysis of the histical reason!
I wanted to do something similar to this PR this when impleneted _get_paths_list but was to lazy to refacor with the yield like you did.

Thanks a lot for this effort.

elif isinstance(dict_list_or_value, list):
for i, v in enumerate(dict_list_or_value):
yield from _extractor_dict_iterator(
v, access_path + (i,), name=name
Copy link
Member

Choose a reason for hiding this comment

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

This is really smart to have the path both with key and index for list!!

@@ -183,6 +184,75 @@ def is_dict_extractor(d: dict) -> bool:
return is_extractor


extractor_dict_element = namedtuple(typename="extractor_dict_element", field_names=["value", "name", "access_path"])
Copy link
Member

Choose a reason for hiding this comment

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

very good idea!

@samuelgarcia samuelgarcia merged commit 47dd371 into SpikeInterface:main Jun 28, 2024
17 checks passed
@h-mayorquin h-mayorquin deleted the recording_dict_iterator branch June 28, 2024 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working core Changes to core module
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants