Repository navigation
feat(client)!: download releases into the local registry - #662
Merged
Merged
Conversation
This was referenced Nov 4, 2026
karhu
force-pushed
the
tnet-157/14-download-store
branch
2 times, most recently
from
November 4, 2026 15:27
aa908c1 to
e01986e
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 4, 2026 15:31
e01986e to
cc51755
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 4, 2026 20:02
cc51755 to
1c8dd29
Compare
This was referenced Nov 4, 2026
karhu
force-pushed
the
tnet-157/14-download-store
branch
2 times, most recently
from
November 7, 2026 17:40
74e5bcf to
c0278e4
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
2 times, most recently
from
November 7, 2026 22:40
291cfc6 to
8c058c4
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 9, 2026 13:56
8c058c4 to
ea10ae3
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 9, 2026 16:18
ea10ae3 to
9c7bf60
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 10, 2026 14:39
9c7bf60 to
48ebb07
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 10, 2026 15:50
48ebb07 to
6247a74
Compare
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 10, 2026 16:24
6247a74 to
a60e678
Compare
download() now copies a release into the local registry, the first local
registry of the list that is not read-only. It resolves the release like
open(). Then plan_download() plans the copies, and run_plan() runs them.
The requested release and each payload source that the local registry
lacks or holds damaged come from the first registry other than the local
registry that provides them. So a release and its payload source can
come from two registries. If the local registry holds a complete copy of
the release, download() copies only the payload sources that the local
registry lacks. A client without a writable local registry raises
TimeFValidationError. A registry over the directory of the local
registry counts as the local registry, also through a symlink or through
a case variant of the name on a volume that ignores case. So the local
registry is never copied onto itself.
download() never builds. For a release that only InstalledConnectors()
provides, it raises TimeNetDatasetNotFoundError, which names open() and
load(). So download() of "latest" fails when an installed connector
declares a newer version than any registry holds. Without a version,
download() takes the first source that serves the dataset, as open()
does. For an exact version that no source provides, an installed
connector that builds another version gives
TimeNetVersionUnavailableError, as in open(). A registry that lists the
release but does not serve its files gives the same access error as
open(). Other errors name the local registry: force=True or a damaged
copy when only the local registry holds the release.
copy_release() takes force=True, which copies the requested release
again into a local registry. A complete payload source stays as it is.
Other files still raise TimeNetVersionConflictError. A registry that is
not local refuses force=True with TimeFValidationError, because it never
writes a published version again. For each release that it copies into a
local registry, copy_release() sends BytesMoved events with the release
as subject. So a build that copies a parent sends them too. A copy step
of a plan passes its force flag to copy_release().
A read of a damaged copy in the local registry ends its TimeNetFileError
with a hint that repairs it: "Copy an intact release into the local
registry with download('<release>')." when another registry provides the
release, or the timenet-build command that builds it again when only the
installed connectors provide it. A damaged copy outside the local
registry gets no hint.
timenet download shows the same output as timenet-build: a status line
when the copy of each release starts and ends, a progress bar for each
release in a terminal, and "Nothing to do" when the local registry
already holds the release and its payload sources. It prints the release
directory in the local registry to stdout. With --force, it copies the
release again, as download(force=True) does. The help of timenet cache
clear now says that --all removes the default local registry with its
downloads.
The interim download() into TIMENET_STORAGE, _reject_unhosted_access()
and BaseRegistry.download_version() are gone.
BREAKING CHANGE: download() copies into the local registry, refuses a
copy in the local registry with other files, and takes progress= events
instead of progress_cb=. BaseRegistry.download_version() is gone. Use
TimeNet.download() instead. download() of "latest" reads the newest
version of every source in the list, so it needs each registry to be
reachable.
Part of TNET-157.
Say only what a caller of download() and copy_release(force=...) needs to know. Part of TNET-157.
Shorter docstrings for the code that this change adds or changes. Part of TNET-157.
Drop tests that cannot fail or repeat other tests, and sharpen the rest. Part of TNET-157.
The glue comments in cache.py now start with TODO(adrian), so a search finds each one that is left. A new TODO(adrian) comment in cli/app.py marks the glue that puts the --registry of timenet download after the store in the list of sources. Part of TNET-157.
karhu
force-pushed
the
tnet-157/14-download-store
branch
from
November 10, 2026 17:41
a60e678 to
b42d4af
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Stack
This stack covers refactoring the internal logic of how releases are resolved during read, download & build, in particular also in the context of parent releases / parent datasets. On top of that it refactors the public TimeNet APIs and CLI interfaces around these actions, to streamline the behavior across them.
This PR
download()copies a release into the store, throughcopy_release(), instead of into a separate storage folder.Details
#661 gives the client a store, the first
LocalRegistryof the list withoutread_only=True, butdownload()still copied intoTIMENET_STORAGEas glue. This PR moves it into the store and makes it the way to repair a damaged copy.download()resolves the release likeopen(). If the store holds a complete copy of the release and of each payload source that it needs, it returns the release directory at once.plan_download()in the coordinator plans the copies, andrun_plan()runs them withcopy_release(). The release comes from the first registry other than the store that provides the exact version. A payload source that this registry lacks comes from the first registry that provides it. So a release and its payload sources can come from different registries. The copy brings along each payload source that the store lacks, and it repairs a damaged copy in the store. A release needs only the payload sources that its manifest lists (the rule of feat(registry)!: copy a release between registries #649), so a payload source comes without its own payload sources.copy_release()andCopySteptakeforce=True, which copies the requested release again into a local registry. For each release that it copies into a local registry, it sendsBytesMovedevents, so a build that copies a parent sends them too.download('<release>'). If only the installed connectors provide it, the hint names thetimenet-buildcommand that builds it again.timenet downloadshows its progress withprogress_renderer(), astimenet-build builddoes: a status line for each release, and a progress bar in a terminal. If there is nothing to copy, it printsNothing to do: '<id>' <version> is already in <store>. It prints the release directory on stdout.BaseRegistry.download_version()goes away.TimeNet.download()andcopy_release()replace it.Design decisions
download()never builds. For a release that onlyInstalledConnectors()provides, it raises an error that namesopen()andload(). An installed connector can declare a newer version than any registry holds. Thendownload('org/name@latest')fails with the default list.download()share that check. The check compares the folders on disk. So a symlink to the store also counts as the store. On a volume that ignores case, so does a path in another case.force=True, because a published version never changes. A different set of files or another card still raisesTimeNetVersionConflictError.download()writes only into the store.Breaking changes
download()copies into the store throughcopy_release(), and refuses a store copy with other files or another card.download()copies each release from the first registry that provides it, so a release and its payload sources can come from different registries.download()takes the newest version of the first source that serves the dataset. With@latest, it asks every source in the list, so each registry must be reachable.download()takesprogress=events instead ofprogress_cb=.download().BaseRegistry.download_version()is gone. UseTimeNet.download()orcopy_release().Stack
Changes later in the stack:
default_sources(),_catalog()forget(),list()andsearch(), the--registrymapping,timenet_connectors.load()andTIMENET_STORAGEas the cache of remote registries are thin glue. feat(config)!: make the default list of sources from three variables #668 and feat(cli)!: take --local-registry, --remote-registry and --auto-build #669 replacedefault_sources(), the--registrymapping and the cache of remote registries. feat!: add timenet.build() and publish() #670 removestimenet_connectors.load(). feat(client)!: replace get() with get_manifest() and get_card() #672 and feat(client)!: list and search every source #673 replace_catalog().Merge message