Skip to content

feat: Metadata.from_metadata#1852

Open
dbirman wants to merge 12 commits into
devfrom
1845-docs-page-for-metadata-inheritance
Open

feat: Metadata.from_metadata#1852
dbirman wants to merge 12 commits into
devfrom
1845-docs-page-for-metadata-inheritance

Conversation

@dbirman

@dbirman dbirman commented Jun 4, 2026

Copy link
Copy Markdown
Member

This PR adds a new function Metadata.from_metadata that simplifies the process of generating derived asset metadata. It implements four rules (see the docs page) that control how metadata is inherited.

@dbirman dbirman linked an issue Jun 4, 2026 that may be closed by this pull request
@dbirman
dbirman requested review from saskiad and tmchartrand June 15, 2026 00:47

@tmchartrand tmchartrand left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll look through in a bit more detail later, but one high-level thought:
I think we should clarify that we still want to inherit subject metadata if there are additional input assets without subject metadata (ie aggregated reference data, templates or the like) in addition to the single-subject assets (and same for sessions).

Does that make sense @saskiad @dbirman ?

@dbirman

dbirman commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

I'll look through in a bit more detail later, but one high-level thought: I think we should clarify that we still want to inherit subject metadata if there are additional input assets without subject metadata (ie aggregated reference data, templates or the like) in addition to the single-subject assets (and same for sessions).

Does that make sense @saskiad @dbirman ?

For example, if someone uses the CCF to do registration that doesn't mean their derived asset is "multi-subject"? I agree we can add that clarification.

@tmchartrand

Copy link
Copy Markdown
Member

Cool I'm pretty sure the code handles this correctly as-is, but we should update docstrings and docs pages and maybe have explicit tests.

@dbirman
dbirman requested a review from tmchartrand July 9, 2026 20:55

@tmchartrand tmchartrand left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks mostly good but I think we at least need to resolve some open questions about the inheritance of names and other fields of data_description.

if value is None:
continue

field_class = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the values should already be instances of the model classes, why retrieve the class at all? can't you just call the classmethods model_validate or model_construct on the instances?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's defensive against a dictionary being passed as a core file. I was being careful because, for example, we know all procedures metadata is invalid. But now that you mention it it's probably overly defensive? I think even if you call model_construct on an invalid procedures dict it will still construct a Procedures object, it will just have dictionaries somewhere inside wherever the validation fails to produce the right objects. I'll double check that this is true before changing it though.

Comment on lines +503 to +507
derived_dd = DataDescription.from_data_description(
first_dd,
process_name=process_name,
source_data=source_names if len(source_names) > 1 else None,
**data_description_kwargs,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think building the datadescription from the first input is correct unless there's only one acquisition (thus all have the same original input name). Even then it's a bit weird that fields like data_summary that may not be shared get inherited effectively randomly (based on order). For multi-acquisition we at least need to drop the datetime part of the name I think (or use the latest one, not sure we have a clear standard), and for multi-subject build a new name following that pattern.

Another issue is making it clear to the user that fields like dd.project should be overridden if the processing is for a different project than the original data (possible here via kwargs but nonobvious).

This is maybe a longer conversation, but I actually think we should be deprecating and/or making private the data_description.from_xxx methods, and replacing with something in the inheritance module that follows the logic outlined above.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think deprecating those is fine and we can drop them in biodata-schema, let me take a pass at making specific helper functions for each situation so that they're really clear and then lets see how it looks.

def from_metadata(
cls,
metadata: "Union[Metadata, List[Metadata]]",
process_name: str,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why does it need the process_name, isn't that already in the Processing object passed to it?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

and why would the process_name be required when the Processing input is optional?

@saskiad saskiad Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

okay, I get what the process_name is now - but I don't think I understand how this works when there is no processing. What should the process_name be then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

good point, I would say that new_processing should be required, and new_process be renamed process_short_name (optional, by default derived via some heuristics from the Processing.name)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If you get a whole bunch of processes how would you know which one to use as the new label for the derived asset? I think it's better to let the user control this.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

at some point we had guidance for people to use the last processing step as the label, BUT, I'm okay letting users control this. I think there might need to be some information in the docs/docstring about how this is being used so that they provide it well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think we want last processing step in general, when you do e.g. spikesorting you would get something really weird. The current final step (in a random asset I checked) is Ephys visualization - experiment1_Record Node 101#Neuropix-PXI-116.46105_recording1, whereas ideally it would say spikesorted. I think that's a general pattern across pipelines.

Maybe we add this (or a similar) description: "Abbreviated name for the process or pipeline that was run. Defaults to 'processed'"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

"Shortened name for the process or pipeline that was run - used in creating name of derived asset. Defaults to 'processed'"

@saskiad saskiad left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm confused on the process_name when there is no processing.

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.

Docs page for metadata inheritance

3 participants