Skip to content

Commit 52b675e

Browse files
committed
Move annex_fingerprint next to AnnexedReadableFile; trim field comments
annex_fingerprint is not specific to NWB files, and living in dandi.support.datalad_fuse it needs no deferred import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qn5WBSiQgoZoL4fytF6nEr
1 parent 2ca1c25 commit 52b675e

4 files changed

Lines changed: 28 additions & 34 deletions

File tree

‎dandi/metadata/nwb.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
from ..misctypes import DUMMY_DANDI_ETAG, Digest, LocalReadableFile, Readable
1717
from ..pynwb_utils import (
1818
_get_pynwb_metadata,
19-
annex_fingerprint,
2019
get_neurodata_types,
2120
get_nwb_version,
2221
ignore_benign_pynwb_warnings,
2322
metadata_cache,
2423
nwb_has_external_links,
2524
)
25+
from ..support.datalad_fuse import annex_fingerprint
2626
from ..utils import find_parent_directory_containing
2727

2828
lgr = get_logger()

‎dandi/pynwb_utils.py‎

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import warnings
2424

2525
import dandischema
26-
from fscacher import PersistentCache, annex_key_fingerprint
26+
from fscacher import PersistentCache
2727
import h5py
2828
import hdmf
2929
import numpy as np
@@ -42,6 +42,7 @@
4242
metadata_nwb_subject_fields,
4343
)
4444
from .misctypes import Readable
45+
from .support.datalad_fuse import annex_fingerprint
4546
from .utils import get_module_version, is_url
4647
from .validate._types import (
4748
Origin,
@@ -73,25 +74,6 @@
7374
)
7475

7576

76-
def annex_fingerprint(source: Any) -> tuple[str, str] | None:
77-
"""
78-
Fingerprint of ``source`` for ``PersistentCache.memoize_path``
79-
80-
Pass it as ``custom_fingerprint`` to cache the results of a function of a
81-
local path or a `Readable` under the git-annex key of a locked annexed
82-
file, paired with its path (see `fscacher.annex_key_fingerprint`), rather
83-
than under ``stat()``: the content of an `AnnexedReadableFile`, which is
84-
not present locally, cannot be ``stat()``-ed. Anything else is handled as
85-
without this.
86-
"""
87-
# Avoid circular import:
88-
from .support.datalad_fuse import AnnexedReadableFile
89-
90-
if isinstance(source, AnnexedReadableFile):
91-
source = source.filepath
92-
return cast("tuple[str, str] | None", annex_key_fingerprint(source))
93-
94-
9577
def _sanitize_nwb_version(
9678
v: Any,
9779
filename: str | Path | None = None,

‎dandi/support/datalad_fuse.py‎

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import subprocess
3434
from typing import IO, Any, cast
3535

36+
from fscacher import annex_key_fingerprint
37+
3638
from ..misctypes import Readable
3739

3840
lgr = logging.getLogger("dandi.support.datalad_fuse")
@@ -74,25 +76,19 @@ def annex_initialized(directory: Path) -> bool:
7476
@dataclass
7577
class AnnexedReadableFile(Readable):
7678
"""
77-
A `Readable` for a (locked) annexed file whose content is not present
78-
locally, which is streamed with datalad-fuse (see the module docstring).
79+
A `Readable` for a (locked) annexed file at ``filepath`` (a broken symbolic
80+
link) whose content is not present locally, which is streamed with
81+
datalad-fuse (see the module docstring). ``url`` is only the first URL
82+
known for the content, for reporting: if it cannot be read, the adapter
83+
tries the others.
7984
8085
Instances are obtained by calling `get_annexed_readable()`.
8186
"""
8287

83-
#: The absolute path of the (broken) symbolic link to the file's content
8488
filepath: Path
85-
86-
#: The git-annex key of the file
8789
key: str
88-
89-
#: The size of the content, as recorded in the key
9090
size: int
91-
92-
#: The first URL that the content may be streamed from (for reporting;
93-
#: the adapter tries the others if it cannot be read from that one)
9491
url: str
95-
9692
adapter: Any = field(repr=False, compare=False)
9793

9894
def open(self) -> IO[bytes]:
@@ -111,6 +107,22 @@ def __str__(self) -> str:
111107
return str(self.filepath)
112108

113109

110+
def annex_fingerprint(source: Any) -> tuple[str, str] | None:
111+
"""
112+
Fingerprint of ``source`` for ``PersistentCache.memoize_path``
113+
114+
Pass it as ``custom_fingerprint`` to cache the results of a function of a
115+
local path or a `Readable` under the git-annex key of a locked annexed
116+
file, paired with its path (see `fscacher.annex_key_fingerprint`), rather
117+
than under ``stat()``: the content of an `AnnexedReadableFile`, which is
118+
not present locally, cannot be ``stat()``-ed. Anything else is handled as
119+
without this.
120+
"""
121+
if isinstance(source, AnnexedReadableFile):
122+
source = source.filepath
123+
return cast("tuple[str, str] | None", annex_key_fingerprint(source))
124+
125+
114126
def get_annexed_readable(path: str | Path) -> AnnexedReadableFile | None:
115127
"""
116128
Return an `AnnexedReadableFile` for streaming the content of the annexed

‎dandi/support/tests/test_datalad_fuse.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import h5py
88
import pytest
99

10-
from ..datalad_fuse import AnnexedReadableFile, get_annexed_readable
11-
from ...pynwb_utils import annex_fingerprint, get_neurodata_types
10+
from ..datalad_fuse import AnnexedReadableFile, annex_fingerprint, get_annexed_readable
11+
from ...pynwb_utils import get_neurodata_types
1212
from ...tests.fixtures import RangeHTTPServer, make_git_annex_dandiset
1313
from ...tests.skip import mark
1414

0 commit comments

Comments
 (0)