Skip to content

Fetch a remote-only series manifest through the custom_file_handler (#87) - #88

Merged
stevevanhooser merged 2 commits into
mainfrom
claude/lazy-fetch-series-manifest
Sep 14, 2026
Merged

stevevanhooser merged 2 commits into
mainfrom
claude/lazy-fetch-series-manifest

Conversation

@stevevanhooser

Copy link
Copy Markdown
Contributor

Summary

Closes #87. Companion port of the DID-matlab fix in VH-Lab/DID-matlab#201 (PR VH-Lab/DID-matlab#202).

A series document that arrived from a store keeping bytes remote — a SyncFiles=false round trip through NDI Cloud, say — lands with its manifest's file_info naming an ndic:// address and no manifest bytes on this machine. _open_series_member's local-only manifest lookup then raised DID:SQLITEDB:FileSeries:ManifestNotLocal without ever offering the manifest's location to the handler, even when the caller had passed one.

This PR adds a dedicated fetch path so a cloud-only manifest resolves the same way every other remote file already does, without changing the fast local path or the no-network contract of cached_path_for_file.

What changed

  • SQLiteDB._fetch_series_manifest_bytes (src/did/implementations/sqlitedb.py) — new protected method, one level up from the existing _fetch_remote_to_cache with the same call shape. Reads the manifest's file_info straight from the document, offers every non-'file' location to the custom_file_handler with the manifest's own uid in the context (seriesName="", mode="open"), and lands the bytes at filecachepath/<manifestUid> under the same single-flight lock the member fetch already holds. Failure returns None so the caller can raise the ordinary ManifestNotLocal.
  • _open_series_member — when _series_manifest_path returns None AND a custom_file_handler was supplied, calls the helper before raising. Fast local path unchanged; exist_doc, no-handler, and no-remote-location cases still get the same ManifestNotLocal shape as before.
  • _series_manifest_path (src/did/database.py) — docstring updated: it is deliberately no-network so cached_path_for_file stays callable from any thread and any process, and the retrieval-authorized path lives on the sqlite implementation.

Tests (tests/test_open_doc_file_series.py)

New TestFetchingAnAbsentManifest class with a stored_series_cloud_only fixture (ndicloud location, ingest=0 — the shape SyncFiles=false produces, uid-keyed handler serves the bytes):

  • test_a_cloud_only_manifest_is_retrieved_through_the_handler — acceptance case. Handler receives the manifest's ndic:// sourcePath with the manifest's own uid in the context, ctx.seriesName="", ctx.mode="open"; the member then reads back byte-for-byte.
  • test_the_manifest_lands_at_filecachepath_after_the_fetch — pins the cache placement (filecachepath/<manifestUid>) that makes the second open cheap.
  • test_different_members_share_one_manifest_fetch — three different member opens result in exactly one manifest handler call.
  • test_a_handler_that_serves_nothing_raises_manifest_not_local — handler-refused case still raises DID:SQLITEDB:FileSeries:ManifestNotLocal, so callers pattern-matching on the identifier keep working.
  • test_no_handler_still_raises_manifest_not_local — the no-handler path is unchanged.

All 41 tests in the file pass; the whole suite (686 passed, 10 skipped, 1 xfailed) passes locally (the bridge-contract module is skipped because pyyaml isn't installed in the run environment — pre-existing, unrelated).

Not this PR

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_015dKpDXCo8VTS4AHiibNnCp


Generated by Claude Code

A series document that arrived from a store keeping bytes remote --
a SyncFiles=false round trip through NDI Cloud, say -- lands with its
manifest's file_info naming an ndic:// address and no manifest bytes on
this machine. _open_series_member's local-only manifest lookup then
raised DID:SQLITEDB:FileSeries:ManifestNotLocal without ever offering
the manifest's location to the handler, even when the caller had passed
one.

Port DID-matlab's fix (VH-Lab/DID-matlab#201, PR #202): add
SQLiteDB._fetch_series_manifest_bytes -- one level up from the existing
_fetch_remote_to_cache with the same call shape. It reads the manifest's
file_info straight from the document, offers every non-'file' location
to the custom_file_handler with the manifest's uid in the context
(seriesName='', mode='open'), and lands the bytes at
filecachepath/<manifestUid> under the same single-flight lock the
member fetch already holds. Success means the next
cached_path_for_uid is a hit, whether the next call is this member,
another member of the same series, or a later session.

_open_series_member's fast local path is unchanged; the fetch only fires
when the manifest is not on disk AND a custom_file_handler was supplied,
so exist_doc and the no-handler cases keep their old shape. When the
handler cannot service the manifest's location, the existing
DID:SQLITEDB:FileSeries:ManifestNotLocal identifier and message are what
gets raised, so callers that pattern-match on it keep working.

_series_manifest_path stays no-network -- the promise that lets
cached_path_for_file resolve files from any thread and any process
without holding the database session. The lazy-fetch path lives on the
sqlite implementation, where the handler already does.

Companion port of VH-Lab/DID-matlab#202. Together they unblock the
NDI-matlab workaround in
ndi.cloud.sync.internal.updateFileInfoForLocalFiles (which installs a
second location on the manifest so the handler has a non-'file' path to
resolve) and will let it retire in a follow-up.
CI's lint job (black --check) reformatted src/did/implementations/sqlitedb.py
and tests/test_open_doc_file_series.py; no code change, only line breaks.

CI's Bridge coverage vs DID-matlab reported drift on database and sqlitedb
because DID-matlab#202 landed the port this PR mirrors. Bump both entries'
matlab_last_sync_hash to 8bea92c (the merge) and record in sync_notes what
was ported. This is the "READ THE DIFF AND PORT THE CHANGE, then set
matlab_last_sync_hash to the commit you examined" step -- the diff is the
one this PR itself carries, so the notes name it directly.

No behavior change from this commit; the port itself is in 449889b.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

_series_manifest_path cannot fetch a remote manifest — mirror VH-Lab/DID-matlab#201

2 participants