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

Joint BIDS-NWB metadata extraction. #1183

Merged
merged 15 commits into from
Jan 30, 2023
Merged
2 changes: 1 addition & 1 deletion dandi/files/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def get_metadata(
digest: Optional[Digest] = None,
ignore_errors: bool = True,
) -> BareAsset:
bids_metadata = BIDSAsset.get_metadata(self)
bids_metadata = BIDSAsset.get_metadata(self, digest, ignore_errors)
nwb_metadata = NWBAsset.get_metadata(self, digest, ignore_errors)
return BareAsset(
**{**bids_metadata.dict(), **nwb_metadata.dict(exclude_none=True)}
Expand Down
12 changes: 8 additions & 4 deletions dandi/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,14 @@ def get_metadata(
bids_dataset_description = find_bids_dataset_description(path)
if bids_dataset_description:
dandiset_path = find_parent_directory_containing("dandiset.yaml", path)
bids_dataset_description = find_bids_dataset_description(path)
df = dandi_file(
Path(path),
dandiset_path,
bids_dataset_description=bids_dataset_description,
)
if not digest:
_digest = "0" * 32 + "-1"
digest = Digest.dandi_etag(_digest)
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
path_metadata = df.get_metadata(digest=digest)
assert isinstance(df, bids.BIDSAsset)
meta["bids_version"] = df.get_validation_bids_version()
Expand All @@ -105,7 +107,7 @@ def get_metadata(
pass
else:
meta[key] = value
elif path.endswith((".NWB", ".nwb")):
if path.endswith((".NWB", ".nwb")):
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
if nwb_has_external_links(path):
raise NotImplementedError(
f"NWB files with external links are not supported: {path}"
Expand Down Expand Up @@ -150,8 +152,10 @@ def get_metadata(
__import__(import_mod)

meta["nd_types"] = get_neurodata_types(path)
else:
raise RuntimeError("Unable to get metadata from non-BIDS, non-NWB asset.")
if not meta:
raise RuntimeError(
"Unable to get metadata from non-BIDS, non-NWB asset: `%s`." % path
)
return meta


Expand Down
13 changes: 13 additions & 0 deletions dandi/tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
BIDS_TESTDATA_SELECTION = [
"asl003",
"eeg_cbm",
"ieeg_epilepsyNWB",
# uncomment once upstream releases fixed spec:
# https://github.com/bids-standard/bids-specification/pull/1346#event-7696972438
# "hcp_example_bids",
Expand Down Expand Up @@ -537,6 +538,18 @@ def bids_dandiset(new_dandiset: SampleDandiset, bids_examples: str) -> SampleDan
return new_dandiset


@pytest.fixture()
def bids_nwb_dandiset(
new_dandiset: SampleDandiset, bids_examples: str
TheChymera marked this conversation as resolved.
Show resolved Hide resolved
) -> SampleDandiset:
copytree(
os.path.join(bids_examples, "ieeg_epilepsyNWB"),
str(new_dandiset.dspath) + "/",
)
(new_dandiset.dspath / "CHANGES").write_text("0.1.0 2014-11-03\n")
return new_dandiset


@pytest.fixture()
def bids_dandiset_invalid(
new_dandiset: SampleDandiset, bids_error_examples: str
Expand Down
28 changes: 28 additions & 0 deletions dandi/tests/test_metadata.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from datetime import datetime, timedelta
import json
import os
from pathlib import Path
import shutil
from typing import Any, Dict, Optional, Tuple, Union

from dandischema.consts import DANDI_SCHEMA_VERSION
Expand Down Expand Up @@ -48,6 +50,32 @@ def test_get_metadata(simple1_nwb: str, simple1_nwb_metadata: Dict[str, Any]) ->
assert target_metadata == metadata


def test_bids_nwb_metadata_integration(bids_examples, tmp_path):
"""
Notes
-----
* Generating data manually here, as fixture workflow calls `new_dandiset`,
which requires spinning up docker:
https://github.com/dandi/dandi-cli/pull/1183#discussion_r1061622910
"""

source_dpath = os.path.join(bids_examples, "ieeg_epilepsyNWB")
dpath = os.path.join(tmp_path, "ieeg_epilepsyNWB")
shutil.copytree(source_dpath, dpath)

file_path = os.path.join(
dpath,
*"sub-01/ses-postimp/ieeg/sub-01_ses-postimp_task-seizure_run-01_ieeg.nwb".split(
"/"
)
)
metadata = get_metadata(file_path)
# This is a key sourced from both NWB and BIDS:
assert metadata["subject_id"] == "01"
TheChymera marked this conversation as resolved.
Show resolved Hide resolved
# This is a key sourced from NWB only:
TheChymera marked this conversation as resolved.
Show resolved Hide resolved
assert metadata["sex"] == "U"


@pytest.mark.parametrize(
"age,duration",
[
Expand Down