|
10 | 10 | import click
|
11 | 11 |
|
12 | 12 | from . import lgr
|
| 13 | +from .bids_utils import is_valid |
13 | 14 | from .consts import DRAFT, dandiset_identifier_regex, dandiset_metadata_file
|
14 | 15 | from .dandiapi import RemoteAsset
|
15 | 16 | from .exceptions import NotFoundError
|
@@ -61,6 +62,20 @@ def upload(
|
61 | 62 | " paths. Use 'dandi download' or 'organize' first."
|
62 | 63 | )
|
63 | 64 |
|
| 65 | + # Pre-validate BIDS datasets before going for individual files. |
| 66 | + bids_datasets = _bids_discover_and_validate(dandiset_.path, validation) |
| 67 | + |
| 68 | + if bids_datasets: |
| 69 | + _bids_datasets = [str(i) for i in bids_datasets] |
| 70 | + if not allow_any_path: |
| 71 | + lgr.info( |
| 72 | + "Enabling --allow-any-path since we detected %s under the following " |
| 73 | + "paths: %s", |
| 74 | + pluralize(len(_bids_datasets), "BIDS dataset"), |
| 75 | + ", ".join(_bids_datasets), |
| 76 | + ) |
| 77 | + allow_any_path = True |
| 78 | + |
64 | 79 | instance = get_instance(dandi_instance)
|
65 | 80 | assert instance.api is not None
|
66 | 81 | api_url = instance.api
|
@@ -383,3 +398,61 @@ def check_replace_asset(
|
383 | 398 |
|
384 | 399 | def skip_file(msg: Any) -> Dict[str, str]:
|
385 | 400 | return {"status": "skipped", "message": str(msg)}
|
| 401 | + |
| 402 | + |
| 403 | +def _bids_discover_and_validate( |
| 404 | + dandiset_path: str, |
| 405 | + validation: Optional[str] = "require", |
| 406 | +) -> List[Path]: |
| 407 | + """Temporary implementation for discovery and validation of BIDS datasets |
| 408 | +
|
| 409 | + References: |
| 410 | + - unification of validation records: https://github.com/dandi/dandi-cli/issues/943 |
| 411 | + - validation "design doc": https://github.com/dandi/dandi-cli/pull/663 |
| 412 | + """ |
| 413 | + from .utils import find_files |
| 414 | + from .validate import validate_bids |
| 415 | + |
| 416 | + bids_descriptions = map( |
| 417 | + Path, find_files(r"(^|[/\x5C])dataset_description\.json$", dandiset_path) |
| 418 | + ) |
| 419 | + bids_datasets = [bd.parent for bd in bids_descriptions] |
| 420 | + if bids_datasets: |
| 421 | + lgr.debug( |
| 422 | + "Detected %s under following paths: %s", |
| 423 | + pluralize(len(bids_datasets), "BIDS dataset"), |
| 424 | + ", ".join(str(i) for i in bids_datasets), |
| 425 | + ) |
| 426 | + |
| 427 | + if validation != "skip": |
| 428 | + if bids_datasets: |
| 429 | + bids_datasets_to_validate = list() |
| 430 | + for p in bids_datasets: |
| 431 | + for bd in bids_datasets: |
| 432 | + try: |
| 433 | + p.relative_to(bd) |
| 434 | + except ValueError: |
| 435 | + try: |
| 436 | + bd.relative_to(p) |
| 437 | + except ValueError: |
| 438 | + pass |
| 439 | + else: |
| 440 | + bids_datasets_to_validate.append(bd) |
| 441 | + else: |
| 442 | + bids_datasets_to_validate.append(bd) |
| 443 | + else: |
| 444 | + bids_datasets_to_validate = bids_datasets |
| 445 | + bids_datasets_to_validate.sort() |
| 446 | + validated_datasets = [] |
| 447 | + for bd in bids_datasets_to_validate: |
| 448 | + validator_result = validate_bids(bd) |
| 449 | + valid = is_valid( |
| 450 | + validator_result, |
| 451 | + allow_missing_files=validation == "ignore", |
| 452 | + allow_invalid_filenames=validation == "ignore", |
| 453 | + ) |
| 454 | + if valid: |
| 455 | + validated_datasets.append(bd) |
| 456 | + return validated_datasets |
| 457 | + else: |
| 458 | + return bids_datasets |
0 commit comments