Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
42 changes: 40 additions & 2 deletions dandi/files/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@

from .bases import GenericAsset, LocalFileAsset, NWBAsset
from .zarr import ZarrAsset
from ..consts import ZARR_MIME_TYPE
from ..consts import ZARR_MIME_TYPE, dandiset_metadata_file
from ..metadata.core import add_common_metadata, prepare_metadata
from ..misctypes import Digest
from ..validate_types import ValidationResult
from ..validate_types import (
ORIGIN_VALIDATION_DANDI_LAYOUT,
Scope,
Severity,
ValidationResult,
)

BIDS_ASSET_ERRORS = ("BIDS.NON_BIDS_PATH_PLACEHOLDER",)
BIDS_DATASET_ERRORS = ("BIDS.MANDATORY_FILE_MISSING_PLACEHOLDER",)
Expand Down Expand Up @@ -114,6 +119,39 @@ def _validate(self) -> None:
# deno-compiled BIDS validator
self._dataset_errors = bids_validate(self.bids_root)

# Add HINT for dandiset.yaml errors
# If any error is about the dandiset metadata file, add a HINT
# suggesting to add it to .bidsignore
additional_hints = []
for result in self._dataset_errors:
is_dandiset_yaml_error = (
result.path is not None
and result.path.relative_to(self.bids_root).as_posix()
== dandiset_metadata_file
)
if is_dandiset_yaml_error:
hint = ValidationResult(
id="DANDI.BIDSIGNORE_DANDISET_YAML",
origin=ORIGIN_VALIDATION_DANDI_LAYOUT,
scope=Scope.DATASET,
origin_result=result,
severity=Severity.HINT,
dandiset_path=result.dandiset_path,
dataset_path=result.dataset_path,
path=result.path,
message=(
f"Consider creating or updating a `.bidsignore` file "
f"in the root of your BIDS dataset to ignore "
f"`{dandiset_metadata_file}`. "
f"Add the following line to `.bidsignore`:\n"
f"{dandiset_metadata_file}"
),
)
additional_hints.append(hint)

# Add hints to the dataset errors
self._dataset_errors.extend(additional_hints)

# Categorized validation results related to individual assets by the
# path of the asset in the BIDS dataset
self._asset_errors = defaultdict(list)
Expand Down
25 changes: 22 additions & 3 deletions dandi/tests/test_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,30 @@ def mock_bids_validate(*args: Any, **kwargs: Any) -> list[ValidationResult]:
assert err.dataset_path is not None
assert err.path.relative_to(err.dataset_path).as_posix() == dandiset_metadata_file

# The error message should be the original BIDS error, not modified
assert err.message is not None
assert err.message.startswith(
f"The dandiset metadata file, `{dandiset_metadata_file}`, is not a part of "
f"BIDS specification."
# We just check that it's about dandiset.yaml, not checking exact message
# since it comes from BIDS validator

# Check that there is also a HINT about .bidsignore
validation_hints = [
r
for r in validation_results
if r.severity is not None and r.severity == Severity.HINT
]

# Assert that there is at least one hint
assert len(validation_hints) >= 1

# Find the hint about .bidsignore for dandiset.yaml
bidsignore_hint = next(
(h for h in validation_hints if h.id == "DANDI.BIDSIGNORE_DANDISET_YAML"),
None,
)
assert bidsignore_hint is not None
assert bidsignore_hint.message is not None
assert ".bidsignore" in bidsignore_hint.message
assert dandiset_metadata_file in bidsignore_hint.message


def test_validate_bids_onefile(bids_error_examples: Path, tmp_path: Path) -> None:
Expand Down
16 changes: 0 additions & 16 deletions dandi/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,22 +186,6 @@ def validate(
):
r_id = id(r)
if r_id not in df_result_ids:
# If the error is about the dandiset metadata file, modify
# the message in the validation to give the context of DANDI
if (
r.path is not None
and r.dataset_path is not None
and r.path.relative_to(r.dataset_path).as_posix()
== dandiset_metadata_file
):
r.message = (
f"The dandiset metadata file, `{dandiset_metadata_file}`, "
f"is not a part of BIDS specification. Please include a "
f"`.bidsignore` file with specification to ignore the "
f"metadata file in your dataset. For more details, see "
f"https://github.com/bids-standard/bids-specification/"
f"issues/131#issuecomment-461060166."
)
df_results.append(r)
df_result_ids.add(r_id)
yield r