Skip to content

feat(config)!: make the default list of sources from three variables - #668

Merged
karhu merged 5 commits into
tnet-157/14b-test-isolationfrom
tnet-157/15-defaults
Nov 10, 2026
Merged

karhu merged 5 commits into
tnet-157/14b-test-isolationfrom
tnet-157/15-defaults

Conversation

@karhu

@karhu karhu commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

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

Three environment variables make the default list of sources, each with one meaning. The new group timenet local replaces timenet cache. timenet local cache clear deletes only the folders that TimeNet marked as its own.

Details

TIMENET_REGISTRY had two meanings: a URL was the registry after the store, and a local path was the store itself. Downloads went to the storage folder and builds to the registry folder, both under ~/.cache/timenet. Cleanup tools delete files there without asking, and a build can take hours to make again.

  • TIMENET_LOCAL_REGISTRY (default ~/.timenet/registry) places the store. TIMENET_REMOTE_REGISTRY (default timenet://) names the registry after it. TIMENET_AUTO_BUILD (default true) puts the installed connectors last.
  • default_sources() reads the variables at call time, and its arguments override them. default_local_registry() returns the store alone. The first entry of the list is always the store.
  • open_registry(), RemoteRegistry and S3Registry take local_registry= instead of cache_dir=. A remote registry reads a complete copy in that local registry only for the same release. For the same release, the two manifests are equal apart from the build environment. Without local_registry=, it reads only its own files. default_sources() passes its store.
  • TIMENET_CACHE (default ~/.cache/timenet) holds only files that a build or a read can make again: the raw downloads in downloads/<dataset_id> and the control databases in control/.
  • settings() raises TimeFValidationError for an empty or blank value and for another invalid value. The message names the variable.
  • When TimeNet creates the downloads or the control folder of the cache, it writes a CACHEDIR.TAG marker file into it. If one of these two folders holds the marker, timenet local cache clear deletes it. It deletes no other folder of the cache. A folder without the marker stays, and a warning names it.
  • timenet local info shows the path and the size of the cache and of the store. timenet local cache info shows the cache alone. timenet local clear deletes the marked folders of the cache and each release in the store, but no other file. Each clear asks first, and --yes skips the question.
  • After a build, TimeNet deletes the raw downloads of the dataset. If the downloads folder has no marker, they stay.
  • If no output is given, timenet-build and timenet_connectors.build() write to the store. An empty or blank --out is an error, not the current directory.
  • The test fixture now sets the new variables instead of TIMENET_HOME.
  • Size: about 2090 changed lines. The variables, the cache and its safety rules read best as one change, because each rule protects a folder that a variable places.

Design decisions

  • The store lies outside ~/.cache, because it holds builds. The cache holds only files that TimeNet can make again, so a cleanup tool can delete all of it.
  • settings() rejects a cache that is the home folder or a folder above it. With TIMENET_CACHE=~ on macOS, the downloads folder of the cache is ~/Downloads, because the volume ignores letter case.
  • settings() rejects a store and a cache that are the same folder or lie in each other. If the store and a folder that clear_cache() deletes overlap, it deletes nothing and raises an error.
  • These checks compare folders by device and inode number, not by the text of the path. So a symlink or a name in other letter case cannot hide an overlap.
  • download() finds the store in the list with the same identity check as settings(). So the two checks cannot disagree on a symlink or a case variant.
  • The marker file proves that TimeNet created the folder. CACHEDIR.TAG is a standard marker, and backup tools skip the folders that hold it. TimeNet does not mark a folder that exists already, because that folder can belong to the user.
  • The group is timenet local, not timenet cache, because it also shows and clears the store, and the store is not a cache. timenet local cache clear clears the cache alone, and timenet local clear clears both. So no clear needs an extra flag.
  • settings() checks each variable on each call, also a variable that an argument overrides. So a wrong value in the shell fails at once, not later in another command.
  • A remote registry reads a copy in the store only for the same release. Another build of the same version can have other files or another card.
  • A remote registry without local_registry= reads no local copy. So a list of sources that the caller gives does not read TIMENET_LOCAL_REGISTRY.
  • The parser of a registry value lives in the private module timenet._registry_uri, which imports only timenet.errors. So timenet.config can import it at the top without a circular import. timenet.registry still exports local_registry_path and TIMENET_REGISTRY_URL.

Breaking changes

  • TIMENET_HOME, TIMENET_STORAGE and TIMENET_REGISTRY are gone. TIMENET_LOCAL_REGISTRY, TIMENET_REMOTE_REGISTRY and TIMENET_AUTO_BUILD replace them.
  • Raw downloads lie in <TIMENET_CACHE>/downloads.
  • default_registry_path() is gone.
  • The timenet cache group and the --all flag of timenet cache clear are gone. The new group timenet local has info, clear, cache info and cache clear. timenet local cache clear deletes only the downloads and control folders that TimeNet marked.
  • TimeNetSettings loses home, storage, registry, home_dir, storage_dir and registry_path.
  • In timenet.cache, cached_datasets(), raw_cache_size() and CachedDataset are gone. stored_releases(), cache_size() and StoredRelease replace them. clear_cache(*, include_registry) is now clear_cache(cache_dir, *, local_registry). It deletes only the folders of the cache and returns a ClearedCache. The new clear_releases(store) deletes the releases in the store and returns a ClearedReleases.
  • open_registry(), RemoteRegistry and S3Registry take local_registry= instead of cache_dir=. Without local_registry=, a remote registry reads no local copy. Before, it read the copies in the storage folder.
  • A remote registry reads a copy in the store only for the same release. Another build of the same version does not count.
  • BaseRegistry.local_root is gone. Use LocalRegistry.root.

Stack

Changes later in the stack:

Merge message

feat(config)!: make the default list of sources from three variables

TIMENET_LOCAL_REGISTRY, TIMENET_REMOTE_REGISTRY and TIMENET_AUTO_BUILD
make the default list of sources, each with one meaning. The local
registry moves to ~/.timenet/registry, outside the cache, because a
build can take hours to make again.

- TIMENET_CACHE holds only files that TimeNet can make again: the raw
  downloads and the control databases.
- timenet local cache clear deletes only the cache folders that hold
  the CACHEDIR.TAG marker of TimeNet. timenet local clear also deletes
  the releases in the local registry.
- settings() refuses a cache that is the home folder or above it, and
  a local registry and a cache that overlap. The checks compare device
  and inode, not path text.
- A remote registry reads a local copy only for the same release.

BREAKING CHANGE: TIMENET_HOME, TIMENET_STORAGE and TIMENET_REGISTRY
are gone. Raw downloads lie in <TIMENET_CACHE>/downloads.

BREAKING CHANGE: The timenet cache group becomes timenet local, with
info, clear, cache info and cache clear.

BREAKING CHANGE: open_registry(), RemoteRegistry and S3Registry take
local_registry= instead of cache_dir=. Without it, a remote registry
reads no local copy. Registries lose local_root.

BREAKING CHANGE: default_registry_path() and the TimeNetSettings
fields home, storage and registry are gone. In timenet.cache,
stored_releases(), cache_size() and clear_releases() replace
cached_datasets() and raw_cache_size(). clear_cache() takes
(cache_dir, *, local_registry).

@karhu
karhu added this pull request to stack #650 November 4, 2026 20:04
This was referenced Nov 4, 2026
@karhu
karhu force-pushed the tnet-157/15-defaults branch 2 times, most recently from 2c0272a to ff315f6 Compare November 5, 2026 08:16
@karhu
karhu force-pushed the tnet-157/15-defaults branch 2 times, most recently from 970f476 to adaf910 Compare November 5, 2026 14:05
Comment thread packages/timenet/src/timenet/config.py Resolved
@karhu
karhu force-pushed the tnet-157/15-defaults branch from e5fc235 to bd04749 Compare November 7, 2026 17:40
@karhu
karhu force-pushed the tnet-157/15-defaults branch from bd04749 to 85a756a Compare November 7, 2026 20:26
@karhu
karhu force-pushed the tnet-157/15-defaults branch from 85a756a to 06f05d1 Compare November 7, 2026 22:40
@karhu
karhu force-pushed the tnet-157/15-defaults branch 2 times, most recently from b77551e to fc54428 Compare November 9, 2026 16:18
@karhu
karhu force-pushed the tnet-157/15-defaults branch from fc54428 to 9ec43cd Compare November 10, 2026 14:39

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings marked 🟡 are optional suggestions and need no follow-up push.

Comment thread packages/timenet/src/timenet/config.py Resolved
Comment thread packages/timenet/src/timenet/config.py Resolved
@karhu
karhu force-pushed the tnet-157/15-defaults branch from 9ec43cd to 04073c9 Compare November 10, 2026 15:50
@karhu
karhu removed this pull request from stack #699 November 10, 2026 15:58

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new blocking issues. 1 optional suggestion (a nit or a note on pre-existing code) was found and not posted. Nothing in this review needs a push before merging.

@karhu
karhu force-pushed the tnet-157/15-defaults branch from 04073c9 to 537d7bf Compare November 10, 2026 16:24
@karhu
karhu added this pull request to stack #772 November 10, 2026 16:24

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped: your organization has reached its API usage limit, so Code Review can't run right now.

An organization admin can review the limit in your organization's usage and billing settings.

Once the limit resets or is raised, someone with write access to this repository can comment @claude review on this pull request to trigger a review.

The default list of sources came from TIMENET_HOME and TIMENET_REGISTRY.
TIMENET_REGISTRY had two meanings: a URL was the registry after the
local registry, and a local path was the local registry itself.
Downloads went to the storage folder and builds to the registry folder,
both under ~/.cache/timenet, where tools delete files without asking.

Now each variable sets one thing. TIMENET_LOCAL_REGISTRY places the
local registry, TIMENET_REMOTE_REGISTRY names the registry after it, and
TIMENET_AUTO_BUILD puts the installed connectors last. default_sources()
reads them at call time, and its arguments override them.
default_local_registry() returns the local registry alone, and the first
entry of the list is always that local registry. The local registry lies
in ~/.timenet/registry, outside ~/.cache, because it holds builds.
TIMENET_CACHE keeps ~/.cache/timenet for files that a build or a read
can make again: the raw downloads in downloads/<dataset_id> and the
control databases in control/.

settings() raises TimeFValidationError for an empty or blank path or
URL and for another invalid value, and the message names the
variable. It loads the settings once, from the arguments merged over
the variables, so an argument replaces an invalid variable.

open_registry(), RemoteRegistry and S3Registry no longer take
cache_dir=, and a remote registry reads only its own files. The planner
alone decides where a release is read from. It resolves each release and
each payload source through the list, and the local registry comes first
in the default list. So a release in the local registry is read there,
and the remote registry gets no request for it. BaseRegistry.local_root
goes away, and LocalRegistry.root names the folder of a local registry.

When TimeNet creates the downloads or the control folder of the
cache, it writes a CACHEDIR.TAG marker file into it. It does not mark
a folder that exists already. After a build, the engine deletes the
raw downloads of the dataset only if the downloads folder holds the
marker.

The timenet cache group is now timenet local, for the local files of
TimeNet. timenet local info shows the path and the size of the cache and
of the local registry. timenet local cache info shows the cache alone.
timenet local cache clear deletes the raw source files and the control
databases of the cache, and only a folder that holds the marker. It
keeps a folder without the marker, for example a folder of the user, and
names it in a warning. A symlinked folder with the marker is unlinked,
and its target stays. timenet local clear deletes the cache and each
release directory in the local registry, but no other file. Each clear
asks first, and --yes skips the question.

In timenet.cache, clear_cache(cache_dir, local_registry=) deletes the
folders of the cache, and clear_releases(store) deletes the releases
through LocalRegistry.releases() and LocalRegistry.remove_release().
Before it deletes anything, clear_cache() runs one private check. It
refuses a cache directory that is the home folder or a folder above it.
With TIMENET_CACHE=~ on macOS, the downloads folder of the cache would
be ~/Downloads. It also refuses a local registry and a folder to delete
that are the same folder or that lie in each other, because the local
registry holds builds. The check compares the folders on disk by device
and inode number, not the text of the paths, so it also sees a symlink,
or a name in other letter case on a volume that ignores case. A build
that removes its raw downloads runs the same check before its first
download. timenet local clear clears the cache first, so a failed check
deletes no release. download() uses the same comparison to tell whether
a registry in the list is the local registry.

The build CLI and timenet_connectors.build() write to the local registry
when no output is given. An empty or blank --out is an error, not the
current directory. This glue stays until the producer API replaces them.

The root conftest.py now gives each test its own local registry, remote
registry and cache through the new variables instead of TIMENET_HOME.

BREAKING CHANGE: TIMENET_HOME, TIMENET_STORAGE and TIMENET_REGISTRY are
gone. TIMENET_LOCAL_REGISTRY (default ~/.timenet/registry) places the
local registry, TIMENET_REMOTE_REGISTRY (default timenet://) names the
registry after it, and TIMENET_AUTO_BUILD (default true) puts the
installed connectors last. TIMENET_CACHE defaults to ~/.cache/timenet,
and raw downloads lie under its downloads folder.
default_registry_path() is gone. The timenet cache group is now timenet
local, with info, clear, cache info and cache clear. clear_cache() takes
the cache directory and local_registry=, and deletes only the folders of
the cache. clear_releases() deletes the releases in the local registry.
open_registry(), RemoteRegistry and S3Registry no longer take
cache_dir=, and a remote registry reads no local copy. To read a local
copy, put its LocalRegistry in the list of sources before the remote
registry. BaseRegistry.local_root and LocalRegistry.local_root are gone.
Use LocalRegistry.root.

Part of TNET-157.
The glue comments of this change now start with TODO(adrian), so a search finds each one that
is left.

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.
Main added two download tests for the retry of rate-limited presigns
(#747). They pass cache_dir= to RemoteRegistry, and this PR removes that
argument. The tests now make the registry without it.

Part of TNET-157.
@karhu
karhu force-pushed the tnet-157/15-defaults branch from 537d7bf to 0311d8e Compare November 10, 2026 17:41
@karhu
karhu merged commit 97d4ec4 into main Nov 10, 2026
4 checks passed
@karhu
karhu deleted the tnet-157/15-defaults branch November 10, 2026 18:24
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.

2 participants