-
[OPIK-6964] [SDK] [DOCS] feat: scope opik export/import to a project (v2) (#7145)
发布于
2026-06-23 12:48:42 +00:00 - [NA] [SDK] [DOCS] feat: scope opik export/import to a project (v2)
Move the
opik exportandopik importCLI commands to the Opik v2 model
where every dataset, prompt, and experiment belongs to a project. Project is
now a required positional (opik export WORKSPACE PROJECT ITEM), the on-disk
layout is project-nested (projects//{datasets,prompts,experiments}
plus traces),project_nameis always threaded into the REST/SDK calls, and
the v1 project-less code paths (Default Project fallbacks, per-trace project
resolution) are removed. The oldprojectitem is renamed totraces.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] [DOCS] refactor: key export/import layout by ID, resolve names via project.json
On-disk export artifacts are now named by ID instead of human names:
projects/<project_id>/ with a project.json ({id, name}), and id-named
dataset_.json / prompt_.json / experiment_.json / trace_.json.
This removes the '/', ':' and whitespace problems of name-based paths (e.g. a
project named "scout:comet-ml/opik"). Human names are stored as data inside the
files. The CLI still takes project/item names; export resolves name->id and
import resolves a project name back to its id-folder by scanning project.json.
Adds --to-project to redirect the destination project on import.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] [DOCS] fix: make import --path symmetric with export (workspace segment)
Import now resolves //projects// — the same layout export
writes — instead of /projects//. This removes the asymmetry that
forced users to pass--path <export-path>/<workspace>on import: the same
--path (including the default opik_exports) now round-trips between export and
import. Updated unit/e2e tests and docs accordingly.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] refactor: drop older-export 'input' fallback in dataset item mapping
import/export targets Opik v2 project-specified data only — no backwards
compatibility. Remove theitem_data.get("input")fallback that tolerated
pre-dataset_item_dataexport files when building the dataset-item id map.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] [DOCS] feat: support cross-workspace import via base-path fallback
Import now resolves the source folder at //projects/ (symmetric
with export, so the same --path round-trips within a workspace) and falls back to
/projects/ when that workspace segment is absent. This enables importing
into a different workspace than the data was exported from: point --path at the
exported workspace directory. Adds resolve_import_base_path() + unit tests and a
docs note.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [DOCS] docs: rename export/import positional TYPE -> ITEM to match CLI
The CLI's positional after PROJECT is ITEM (subcommand metavar "ITEM [ARGS]...",
"Missing ITEM" error, usage "WORKSPACE PROJECT ITEM [NAME]"). Align both docs to
ITEM so users don't confuse it with a "type" field.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] fix: import exits non-zero when items fail to import
Previously
opik importreported per-item failures only as a warning and exited
0, masking errors (e.g. invalid trace JSON, or the whole-directory failure path
that reports under projects_errors). Both_import_by_typeandimport_allnow
sum every*_errorscounter across all phases and exit 1 when any are present,
so failures surface with a non-zero exit code. Adds a regression test.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] [DOCS] refactor: address PR review — harden project.json read, dedup import lookup, docs note
- imports/utils._read_project_metadata_name: guard against non-object JSON and
non-string "name" so a malformed project.json can't crash project discovery. - Extract resolve_import_project_root(path, workspace, project_name, to_project)
shared by import_all and _import_by_type so the source lookup + not-found
messaging + destination resolution stay in one place. - docs: add the "maintained by hand" maintenance note to the Example Workflow
(covers the pandas CSV snippet).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] fix: don't mark import manifest complete on partial failure; count recreated-experiment errors
Addresses PR review (manifest/error-handling):
- Compute total_errors before manifest.complete() in both _import_by_type and
import_all, and only complete() when total_errors == 0. A partial failure now
leaves the manifest in_progress so a non---force rerun resumes/retries instead
of short-circuiting on manifest.is_completed. - recreate_experiments() now returns (successful, failed); import_traces_from_directory
surfaces experiments/experiments_errors in its stats so traces imports that
recreate experiments don't exit 0 on a partial failure. - Add regression test that a failed import leaves the manifest incomplete.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] test: verify failed-import retryability via public behavior; fix comment typo
Address PR review nits:
- Rewrite the manifest-incomplete-on-failure test to assert observable behavior
(a rerun without --force re-invokes the importer) instead of poking the
internal MigrationManifest.is_completed, per .agents/skills/python-sdk/testing.md. - Fix a "non---force" typo in an imports/__init__.py comment.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] refactor: extract shared finalize_import() for import flush/complete
Both _import_by_type and import_all ran identical flush + failed-upload checks
and the total_errors==0 gate on manifest.complete(). Extract that into
imports/utils.finalize_import(manifest, client, total_errors, dry_run) so
resume/manifest behavior stays in one place (the per-type vs. aggregate summary
messaging remains in each caller). No behavior change.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] [DOCS] fix: per-destination import manifest; address review
Addresses JetoPistola review:
- BLOCKER: the resume/completion manifest was keyed only to the source folder,
so importing one export into different --to-project targets shared one manifest
(a clean import into A made a later import into B short-circuit on
"already completed"; a partial import into A would resume into B). The manifest
is now keyed by destination via destination_manifest_dir(project_root, dest)
(hashed, names may contain / :). Regression test: import into A then B both run. - Switch the import prompt path to client.create_prompt()/create_chat_prompt()
instead of the deprecated opik.Prompt()/ChatPrompt() constructors. - Warn in find_project_export_dir when >1 exported folder records the same
project name (ambiguous resolution). - Docs: manifest now lives under projects//import_manifests//.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] fix: keep migration manifest keyed to project_root; extract setup_import_manifest
Fixes a regression from the per-destination manifest change: passing the
per-destination subdir as MigrationManifest.base_path made file keys resolve
relative_to() that subdir, but exported files live under project_root/... — so
mark_file_completed()/is_file_completed() raised ValueError and broke resume
tracking (mocked unit tests didn't catch it; live import would).- MigrationManifest gains an optional manifest_path so the SQLite file can live
in the per-destination subdir while base_path stays project_root (the key root
for relative file paths). mkdir the manifest file's parent, not base_path. - Extract setup_import_manifest(project_root, dest, dry_run, force) — used by
both import_all and _import_by_type — which builds the manifest correctly and
runs the start/resume/force lifecycle, returning (manifest, already_completed).
This also dedups the manifest-lifecycle block flagged in review. - Add a regression test that files under project_root are keyable while the db
lives in the per-destination subdir.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- [NA] [SDK] fix: --force no longer resets a non-existent manifest; rename tests to convention
Address PR review:
- setup_import_manifest captured manifest existence AFTER constructing
MigrationManifest, which creates the SQLite file — so a first--forcerun saw
exists()==True and warned/reset against a manifest that never existed. Capture
existence before construction. Tests cover both fresh-force (no warn/reset) and
force-with-existing (warn/reset). - Rename the two new manifest tests to the required
test_WHAT__CASE__EXPECTED_RESULT format.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
- test(cli): scope export/import e2e verification reads to the project
The datasets/prompts/chat-prompts happy-flow e2e tests created data with
project_name=source_project_name but verified it via project-less
get_datasets()/search_prompts()/get_chat_prompt(), which resolve to the
client's default project. The default project is never created, so
get_datasets 404'd and search_prompts returned nothing — three failures
in CI. Scope the verification reads to source_project_name to match the
v2 project-scoped model the rest of the test already uses.Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Douglas Blank doug@comet.com
Co-authored-by: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-authored-by: Alexander Kuzmik alexander.kuzmik99@gmail.com下载附件