Skip to content

feat!: add timenet.build() and publish() - #670

Merged
karhu merged 3 commits into
tnet-157/16-cli-flagsfrom
tnet-157/17-producer-api
Nov 10, 2026
Merged

karhu merged 3 commits into
tnet-157/16-cli-flagsfrom
tnet-157/17-producer-api

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

The new module timenet.producer adds timenet.build() and timenet.publish(), and the shell gets timenet publish. timenet_connectors.build() and load() are gone.

Details

A build from Python went through timenet_connectors.build(). It took fetch_from and build_parents instead of a list of sources, and it wrote to the store only through glue. Publishing a release had no function of its own, and only the build CLI copied a release to a remote --out.

  • build() builds a release into a writable local registry with the installed connector that claims it, and returns the release directory. Missing parents and payload sources come from sources.
  • build() takes open_access_only. If it is set, a plan that needs a release without open access raises TimeNetAccessError before any step runs.
  • publish() copies a complete release and the payload sources that its manifest lists from a registry, by default the store, to dest. It returns the release that it copied.
  • The defaults of build() come from the environment at call time. local_registry is TIMENET_LOCAL_REGISTRY, and sources is the default list. With sources, the sources come only from the argument.
  • timenet publish DATASET --dest URL copies a release with timenet.publish(). The release comes from the store, or from the registry that --source names.
  • An empty or blank --dest raises TimeNetRegistryError, and timenet publish writes nothing. It never means the current directory.
  • as_release_sources() checks and opens the lists of TimeNet(sources=...) and of the sources of build(). Each message names its argument.
  • The package timenet imports nothing from timenet_connectors, and the two functions load on first use. A ruff rule checks the first, and a subprocess test checks the second.
  • timenet also exports TimeNet, LocalRegistry and InstalledConnectors. They load on first use too, so import timenet is enough to make a client with its sources.
  • timenet_connectors.build() and load() are gone, with their hint and the glue that wrote to the store. The tests, the example and the API reference use the new names.
  • Size: about 1160 changed lines. The two functions, the command and the removal of the old functions must land together. Otherwise the old functions keep a second way to build.

Design decisions

  • A local_registry that is remote or read-only raises TimeFValidationError, because a build always lands in a writable local registry. A blank value or an unknown scheme raises TimeNetRegistryError.
  • A registry URL in the list reuses the complete copies of the same releases in the store of the call. So the build does not download what it holds.
  • publish() never changes a published version. Other files or another card in dest raise TimeNetVersionConflictError, and the same release copies nothing.
  • publish() reads "latest" from the source. If the release is missing, the error names the source, so it shows where publish() looked.
  • timenet publish takes the release from the store by default, because a build lands there. If the store lacks it, the error says to run timenet-build build or timenet download.
  • The functions wrap the internal coordinator and add no planning of their own, so Python and the CLI cannot plan in different ways.

Breaking changes

  • timenet_connectors.build() and timenet_connectors.load() are gone.

Stack

Changes later in the stack:

  • docs: update the docs for the build coordinator #683 holds the doc changes of this PR.
  • timenet-build build still takes --out, --fetch-from and --build-parents. A bare timenet-build and timenet.build() take their parents from different defaults until the PR on timenet-build --publish-to replaces the flags.
  • get(), list() and search() still ask one registry through _catalog(). The PRs on inspection and on list and search replace them.

Merge message

feat!: add timenet.build() and publish()

timenet.build() and timenet.publish() give Python one way to build
into the local registry and to publish a release, with the same list
of sources as the client. The shell gets timenet publish.

- build() builds a release with the installed connector that claims
  it and returns the release directory. Missing parents and payload
  sources come from sources.
- With open_access_only, a plan that needs a release without open
  access fails before any step runs.
- publish() copies a complete release and its payload sources from the
  local registry, or from source, to dest. It never changes a
  published version.
- The defaults come from the environment at call time.
- timenet imports nothing from timenet_connectors, and the new names
  load on first use.

BREAKING CHANGE: timenet_connectors.build() and
timenet_connectors.load() are gone. Use timenet.build() and
TimeNet().load().

@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/17-producer-api branch from 17d6e02 to c857696 Compare November 5, 2026 07:24
@karhu
karhu force-pushed the tnet-157/17-producer-api branch 3 times, most recently from 86f5f9c to 61cc2df Compare November 5, 2026 10:57
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 61cc2df to 781ecd0 Compare November 5, 2026 14:05
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 711597e to 7de08e6 Compare November 7, 2026 15:20

@TimoStoff TimoStoff left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM!

Comment thread packages/timenet/src/timenet/client.py Resolved
Comment thread packages/timenet/src/timenet/cli/app.py Resolved
Comment thread packages/timenet/src/timenet/cli/app.py Resolved
Comment thread packages/timenet/tests/test_producer.py Resolved
Comment thread packages/timenet/tests/test_producer.py Resolved
Comment thread packages/timenet/tests/test_cli.py Resolved
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 7de08e6 to 1d8c4a6 Compare November 7, 2026 16:27
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 1d8c4a6 to 23a054c Compare November 7, 2026 17:40
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 23a054c to 254a1e4 Compare November 7, 2026 20:26
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 254a1e4 to ce19919 Compare November 7, 2026 22:40
@karhu karhu changed the title feat!: add timenet.build(), plan_build() and publish() feat!: add timenet.build() and publish() Nov 9, 2026
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from ce19919 to a4a77e0 Compare November 9, 2026 13:56
@karhu
karhu force-pushed the tnet-157/17-producer-api branch 2 times, most recently from 894c7a8 to e658cb5 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.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

@karhu
karhu force-pushed the tnet-157/17-producer-api branch from e658cb5 to 5b98f35 Compare November 10, 2026 15:50

@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 found no issues

No high-confidence issues detected in this change.

@karhu
karhu removed this pull request from stack #699 November 10, 2026 15:58
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from 5b98f35 to b6c45e5 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.

A build from Python went through timenet_connectors.build(). It took
fetch_from and build_parents instead of a list of sources, and it wrote
to the local registry only through glue. Publishing a release had no
function of its own. Only the build CLI copied a release to a remote
--out. The shell had no command to copy a release out of the local
registry.

The new module timenet.producer adds build() and publish(). The timenet
package exports them, together with TimeNet, LocalRegistry and
InstalledConnectors, and loads each on first use. The plan and its steps
stay internal. build() builds a release into the local registry and
returns its directory, like TimeNet.download(). Missing parents and
payload sources come from sources, the same name as in TimeNet. Without
sources, the build takes the whole default list, and the planner leaves
the local registry out of the sources of its copies and builds. With
open_access_only=True, build() refuses a plan that needs a release
without open access, before any step runs. publish() takes a dataset ID
or an exact DatasetRef, which needs no lookup in the source. It copies a
complete release and its payload sources to dest. A published version
cannot change, so other files in dest raise TimeNetVersionConflictError.

The defaults of build() come from the environment at call time. A
local_registry that is remote or read-only raises
TimeFValidationError, which points to publish().

timenet publish DATASET --dest URL|PATH copies a release with publish().
The release comes from the local registry or from the registry of
--source. An empty --dest is an error, not the current directory.

timenet_connectors.build() and load() are gone, with their glue. The
tests, the example and the API reference use the new names.

BREAKING CHANGE: timenet_connectors.build() and
timenet_connectors.load() are gone. Build with timenet.build() and
read with TimeNet().load().

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.
@karhu
karhu force-pushed the tnet-157/17-producer-api branch from b6c45e5 to f2b6dcf Compare November 10, 2026 17:41
@karhu
karhu merged commit c5908cc into main Nov 10, 2026
4 checks passed
@karhu
karhu deleted the tnet-157/17-producer-api 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