ArtifactDraft

ArtifactDraft#

class ArtifactDraft#

Build an Artifact by adding typed data and metadata, then commit it locally.

A draft collects the layers and annotations that will become an Artifact. The Artifact class contains a complete executable example that creates a problem and candidate, adds JSON and a table, exports an archive, and reads it in a separate process with an empty registry.

Choose a name#

Constructor

Use

new()

Supply an explicit OCI image reference

new_anonymous()

Generate a local name when you do not need a distribution name

for_github()

Build a GitHub Container Registry reference and record its source repository

Every constructor uses the Local Registry. An anonymous name is still a persistent registry entry, not a temporary file. Its timestamp records the sender’s local clock without a timezone marker; do not use that part of the name as an absolute timestamp across machines. new_anonymous() describes the complete naming convention.

Add data and record its meaning#

Use add_instance(), add_parametric_instance(), add_solution(), or add_sample_set() for OMMX objects. Their payload formats and OMMX annotations are handled by the SDK. add_json(), add_dataframe(), and add_ndarray() store JSON, pandas tables, and NumPy arrays. Their annotation keywords use org.ommx.user. by default; title="analysis" becomes the org.ommx.user.title annotation. add_annotation() adds manifest-level metadata rather than a layer annotation.

Adding data returns a Descriptor. Retain its digest when you need to identify that exact layer in a separate note or application record. Adding several problems and results does not establish their relationships automatically. add_layer() is the low-level operation for data with an explicit media type and byte representation.

Commit, export, and distribute#

commit() finalizes the layer list and creates a registry-resident Artifact. The draft is consumed by this operation; use a new draft for different content. Layer data can already have been written locally while building the draft, so an uncommitted draft does not mean that no disk writes occurred.

Committing does not write a .ommx archive or contact a remote registry. Call save() on the returned Artifact to export a file, or push() to distribute it. A receiver imports an archive with import_archive() before reading its layers. The complete exchange example in Artifact demonstrates these boundaries without a solver or remote service.

add_annotation(key: str, value: str) → None#

Add annotation to the artifact itself.

add_dataframe(df: Any, *, annotation_namespace: str = 'org.ommx.user.', **annotations: Any) → Descriptor#

Add a pandas DataFrame to the artifact with parquet format.

>>> import pandas as pd
>>> df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})

The remaining operations use the persistent Local Registry.

>>> draft = ArtifactDraft.temp()
>>> _desc = draft.add_dataframe(df, title="test_dataframe")
>>> artifact = draft.commit()
>>> layer = artifact.layers[0]
>>> print(layer.media_type)
application/vnd.apache.parquet
add_instance(instance: Instance) → Descriptor#

Add an Instance to the artifact with annotations.

>>> from ommx import Instance
>>> instance = Instance.minimize()
>>> instance.title = "test instance"

The remaining operations use the persistent Local Registry.

>>> draft = ArtifactDraft.temp()
>>> desc = draft.add_instance(instance)
>>> print(desc.annotations['org.ommx.v1.instance.title'])
test instance
add_json(obj: Any, *, annotation_namespace: str = 'org.ommx.user.', **annotations: Any) → Descriptor#

Add a JSON object to the artifact.

>>> obj = {"a": 1, "b": 2}

The remaining operations use the persistent Local Registry.

>>> draft = ArtifactDraft.temp()
>>> _desc = draft.add_json(obj, title="test_json")
>>> artifact = draft.commit()
>>> layer = artifact.layers[0]
>>> print(layer.media_type)
application/json
add_layer(media_type: str, blob: bytes, annotations: Mapping[str, str] = {}) → Descriptor#

Low-level API to add any type of layer to the artifact with annotations.

Use add_instance() or other high-level methods if possible.

add_ndarray(array: Any, *, annotation_namespace: str = 'org.ommx.user.', **annotations: Any) → Descriptor#

Add a numpy ndarray to the artifact with npy format.

>>> import numpy as np
>>> array = np.array([1, 2, 3])

The remaining operations use the persistent Local Registry.

>>> draft = ArtifactDraft.temp()
>>> _desc = draft.add_ndarray(array, title="test_array")
>>> artifact = draft.commit()
>>> layer = artifact.layers[0]
>>> print(layer.media_type)
application/vnd.numpy
>>> print(layer.annotations)
{'org.ommx.user.title': 'test_array'}
add_parametric_instance(instance: ParametricInstance) → Descriptor#

Add a ParametricInstance to the artifact with annotations.

add_sample_set(sample_set: SampleSet) → Descriptor#

Add a SampleSet to the artifact with annotations.

add_solution(solution: Solution) → Descriptor#

Add a Solution to the artifact with annotations.

commit() → Artifact#

Commit the artifact draft.

Return a registry-resident Artifact; exporting a file and distributing it use Artifact.save() and Artifact.push(). See Artifact for the complete file-exchange example.

Raises RuntimeError for registry or storage failures and when the draft has already been committed.

for_github(org: str, repo: str, name: str, tag: str) → ArtifactDraft#

An alias for new() to create a new artifact in local registry with GitHub Container Registry image name.

This also sets the org.opencontainers.image.source annotation to the GitHub repository URL.

new(image_name: str) → ArtifactDraft#

Create a new artifact draft with an explicit image name. The artifact is published into the user’s persistent SQLite Local Registry on commit(); call Artifact.save(path) on the returned handle if you also want a .ommx archive file for sharing.

>>> from ommx.testing import SingleFeasibleLPGenerator, DataType
>>> generator = SingleFeasibleLPGenerator(3, DataType.INT)
>>> instance = generator.get_v1_instance()
>>> import uuid
>>> image_name = f"ghcr.io/jij-inc/ommx/single_feasible_lp:{uuid.uuid4()}"

The remaining operations use the persistent Local Registry.

>>> draft = ArtifactDraft.new(image_name)
>>> _desc = draft.add_instance(instance)
>>> artifact = draft.commit()
>>> print(artifact.image_name)
ghcr.io/jij-inc/ommx/single_feasible_lp:...

Raises ValueError when image_name is not a valid OCI image reference. Registry and storage failures raise RuntimeError.

new_anonymous() → ArtifactDraft#

Create a new artifact draft without inventing an image name.

UX shortcut: a synthetic image name of the form <registry-id8>.ommx.local/anonymous:<local-timestamp>-<nonce> is generated when the draft is created and used as the SQLite Local Registry key. v3 stores every artifact in the registry, so anonymous artifacts still need a key — the registry-id prefix (a random 8-hex truncation of a UUID generated once per LocalRegistry and persisted in its SQLite metadata) identifies which registry produced the artifact (useful when archives are shared), the local-time timestamp lets you identify entries by when they were created, and the 12-hex (48-bit) random nonce keeps concurrent anonymous drafts (MINTO-style scripts emitting many artifacts per second) collision-free regardless of clock resolution. Use Artifact.image_name to read the synthesized name back. The .local mDNS TLD prevents an accidental push from leaking to a real remote registry. Use ommx prune-anonymous to clean accumulated entries.

The timestamp is the caller’s local time with no timezone marker. If an anonymous archive is shared with someone in a different timezone, the recipient will see the same digits but interpret them as their own local time — the time component loses absolute meaning across machines. Anonymous artifacts are not intended for cross-timezone sharing; pick an explicit name via ArtifactDraft.new(...) if absolute time matters.

Call Artifact.save(path) on the returned handle to also write a .ommx archive file for sharing.

>>> from ommx.testing import SingleFeasibleLPGenerator, DataType
>>> generator = SingleFeasibleLPGenerator(3, DataType.INT)
>>> instance = generator.get_v1_instance()

The remaining operations use the persistent Local Registry.

>>> draft = ArtifactDraft.new_anonymous()
>>> _desc = draft.add_instance(instance)
>>> artifact = draft.commit()
>>> assert ".ommx.local/anonymous:" in artifact.image_name
temp() → ArtifactDraft#

Create a new artifact draft under a random ttl.sh image name. Insecure; for tests only. ttl.sh is a public registry that expires images after one hour.

This example writes to the persistent Local Registry and is not executed as a doctest.

>>> draft = ArtifactDraft.temp()
>>> artifact = draft.commit()
>>> print(artifact.image_name)
ttl.sh/...-...-...-...-...:1h