File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ # 0.74.3 (Sat Feb 14 2026)
2+
3+ #### 🐛 Bug Fix
4+
5+ - bf: pass aiohttp timeouts to fsspec to fix test hang [ #1795 ] ( https://github.com/dandi/dandi-cli/pull/1795 ) ([ @yarikoptic ] ( https://github.com/yarikoptic ) )
6+ - Enhance dandiset metadata error messages [ #1790 ] ( https://github.com/dandi/dandi-cli/pull/1790 ) ([ @yarikoptic ] ( https://github.com/yarikoptic ) [ @yarikoptic-gitmate ] ( https://github.com/yarikoptic-gitmate ) )
7+ - Fix type annotation in upload sync path prefix calculation [ #1794 ] ( https://github.com/dandi/dandi-cli/pull/1794 ) ([ @yarikoptic ] ( https://github.com/yarikoptic ) [ @yarikoptic-gitmate ] ( https://github.com/yarikoptic-gitmate ) )
8+ - Fix macOS-15-intel CI failures: h5py and opencv-python regressions [ #1783 ] ( https://github.com/dandi/dandi-cli/pull/1783 ) ([ @yarikoptic ] ( https://github.com/yarikoptic ) )
9+
10+ #### 📝 Documentation
11+
12+ - Add module docstrings to validation and NWB utilities [ #1789 ] ( https://github.com/dandi/dandi-cli/pull/1789 ) ([ @yarikoptic ] ( https://github.com/yarikoptic ) [ @yarikoptic-gitmate ] ( https://github.com/yarikoptic-gitmate ) )
13+
14+ #### Authors: 2
15+
16+ - GitMate for @yarikoptic ([ @yarikoptic-gitmate ] ( https://github.com/yarikoptic-gitmate ) )
17+ - Yaroslav Halchenko ([ @yarikoptic ] ( https://github.com/yarikoptic ) )
18+
19+ ---
20+
121# 0.74.2 (Fri Jan 30 2026)
222
323#### 🐛 Bug Fix
Original file line number Diff line number Diff line change @@ -42,7 +42,11 @@ def __init__(
4242 if not allow_empty and not os .path .lexists (
4343 self .path_obj / dandiset_metadata_file
4444 ):
45- raise ValueError (f"No dandiset at { path } " )
45+ raise ValueError (
46+ f"No dandiset at { path } . "
47+ f"The directory does not contain a '{ dandiset_metadata_file } ' file. "
48+ "Use 'dandi download' to download a dandiset or check the path."
49+ )
4650 self .metadata : dict | None = None
4751 self ._metadata_file_obj = self .path_obj / dandiset_metadata_file
4852 self ._load_metadata ()
@@ -139,11 +143,17 @@ def _get_identifier(metadata: dict) -> str | None:
139143 @property
140144 def identifier (self ) -> str :
141145 if self .metadata is None :
142- raise ValueError ("No metadata record found in Dandiset" )
146+ raise ValueError (
147+ f"No metadata record found in Dandiset at { self .path } . "
148+ f"The '{ dandiset_metadata_file } ' file may be empty or corrupted. "
149+ "Use 'dandi download' to re-download the dandiset metadata."
150+ )
143151 id_ = self ._get_identifier (self .metadata )
144152 if not id_ :
145153 raise ValueError (
146- f"Found no dandiset.identifier in metadata record: { self .metadata } "
154+ f"Found no dandiset.identifier in metadata record. "
155+ f"The '{ dandiset_metadata_file } ' file must contain an 'identifier' field. "
156+ f"Metadata: { self .metadata } "
147157 )
148158 return id_
149159
Original file line number Diff line number Diff line change @@ -345,10 +345,27 @@ def open(self) -> IO[bytes]:
345345 # Optional dependency:
346346 import fsspec
347347
348+ from aiohttp import ClientTimeout
349+
348350 # We need to call open() on the return value of fsspec.open() because
349351 # otherwise the filehandle will only be opened when used to enter a
350352 # context manager.
351- return cast (IO [bytes ], fsspec .open (self .url , mode = "rb" ).open ())
353+ #
354+ # Pass explicit timeouts to aiohttp to prevent indefinite hangs in
355+ # fsspec's sync() wrapper. Without these, a stalled connection to S3
356+ # (or minio in tests) causes fsspec's background IO thread to block
357+ # forever, which in turn blocks the calling thread in
358+ # threading.Event.wait() — see https://github.com/fsspec/filesystem_spec/issues/1666
359+ return cast (
360+ IO [bytes ],
361+ fsspec .open (
362+ self .url ,
363+ mode = "rb" ,
364+ client_kwargs = {
365+ "timeout" : ClientTimeout (total = 120 , sock_read = 60 , sock_connect = 30 )
366+ },
367+ ).open (),
368+ )
352369
353370 def get_size (self ) -> int :
354371 return self .size
Original file line number Diff line number Diff line change 1+ """Utilities for working with NWB (Neurodata Without Borders) files.
2+
3+ This module provides helper functions for reading, validating, and extracting
4+ metadata from NWB files using PyNWB. Features include:
5+ - NWB file I/O with caching
6+ - Metadata extraction for DANDI schema
7+ - Version compatibility checking
8+ - External link detection
9+ - Validation against NWB standards
10+ """
11+
112from __future__ import annotations
213
314from collections import Counter
Original file line number Diff line number Diff line change @@ -1145,6 +1145,7 @@ def test_nwb2asset(simple2_nwb: Path) -> None:
11451145 )
11461146
11471147
1148+ @pytest .mark .timeout (120 )
11481149@pytest .mark .xfail (reason = "https://github.com/dandi/dandi-cli/issues/1450" )
11491150def test_nwb2asset_remote_asset (nwb_dandiset : SampleDandiset ) -> None :
11501151 pytest .importorskip ("fsspec" )
Original file line number Diff line number Diff line change 1515from collections .abc import Iterator , Sequence
1616from contextlib import ExitStack
1717from enum import Enum
18- from functools import reduce
1918import io
2019import os .path
2120from pathlib import Path
@@ -504,7 +503,7 @@ def upload_agg(*ignored: Any) -> str:
504503 for p in paths :
505504 rp = os .path .relpath (p , dandiset .path )
506505 relpaths .append ("" if rp == "." else rp )
507- path_prefix = reduce ( os .path .commonprefix , relpaths ) # type: ignore[arg-type]
506+ path_prefix = os .path .commonprefix ( relpaths )
508507 to_delete = []
509508 for asset in remote_dandiset .get_assets_with_path_prefix (path_prefix ):
510509 if any (
Original file line number Diff line number Diff line change 1+ """Validation of DANDI datasets against schemas and standards.
2+
3+ This module provides validation functionality for dandisets, including:
4+ - DANDI schema validation
5+ - BIDS standard validation
6+ - File layout and organization validation
7+ - Metadata completeness checking
8+ """
9+
110from __future__ import annotations
211
312from collections .abc import Iterator
You can’t perform that action at this time.
0 commit comments