-
[OPIK-6964] [SDK] feat: add --to-workspace option to opik import; fix data loss gaps (#7278)
发布于
2026-07-01 16:57:08 +00:00 - [NA] [SDK] feat: add --to-workspace option to opik import for cross-workspace imports
Previously the WORKSPACE positional arg served double duty: locating
exported files on disk and setting the destination API workspace.
Importing into a different workspace required pointing --path at the
source workspace directory as a workaround.--to-workspace is now a subcommand-level option (alongside --to-project)
on all import subcommands (all, traces, dataset, experiment, prompt).
WORKSPACE still resolves the on-disk path; --to-workspace overrides the
workspace used when calling opik.Opik(). This lets users write:opik import src-workspace my-project all
--to-workspace dest-workspace --to-project new-projectCo-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
- [NA] [SDK] fix: include dest workspace in import manifest key, fix test naming
destination_manifest_dirnow hashes<dest_workspace>:<dest_project>
instead of just<dest_project>, so importing the same exported project
into different--to-workspacetargets keeps independent resume/completion
state and cannot short-circuit viamanifest.is_completed- Updated
setup_import_manifestsignature to acceptdestination_workspace
and threaded it through both_import_by_typeandimport_all - Renamed test to follow
test_WHAT__CASE__EXPECTEDconvention and switched
from directimport_all()call toCliRunner.invoke(import_group, ...)
to exercise the public CLI surface - Fixed
_manifest_dirtest helper to pass workspace so its hash matches
the new key format
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
- [NA] [SDK] fix: retry attachment 429s during export instead of dropping the trace
_fetch_attachments and _download_attachment_file convert ApiError 429s
into OpikCloudRequestsRateLimited before raising. This exception is not
an ApiError or httpx.* type, so _allowed_to_retry returned False and the
retry decorator did nothing — the 429 propagated straight to the thread
pool handler, which printed "Unexpected error processing trace" and
skipped the trace without retrying.Fix:
- Add _export_allowed_to_retry that extends the standard predicate to
also match OpikCloudRequestsRateLimited - Update _export_wait_duration to read retry_after directly from the
exception (attachment ops already extract it from response headers) - Apply @_export_rest_retry to _fetch_attachments and
_download_attachment_file so attachment 429s wait and retry up to 8
times before giving up, consistent with trace/span fetching
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
- [NA] [SDK] fix: prevent silent data loss in export CLI (8 error-handling gaps)
Audit of the export CLI found 8 places where API errors were silently
swallowed, causing traces, experiments, datasets, or prompts to be
dropped with no indication in the manifest or exit code.HIGH
- experiment._fetch_trace_data: add @_export_rest_retry so 429/5xx
trigger wait-and-retry instead of being caught and returned as None
(which was counted as a skip and allowed manifest.complete() to fire).
Only genuine 404s now return None. - experiment.export_experiment_by_id: re-raise instead of swallowing
all exceptions; callers in all.py already set had_errors=True when
the future raises. - all._fetch_experiments_page_raw: add @_export_rest_retry and convert
429 to OpikCloudRequestsRateLimited; remove silent return ([], 0)
so an entire experiments page is no longer silently dropped on 429.
MEDIUM
- project._process_trace: only call manifest.mark_trace_downloaded()
when attachment download also succeeded, so a re-run can retry
missing attachments without --force. - dataset.export_experiment_datasets: track and return an error count
so callers can distinguish "0 exported" from "all failed". - prompt.export_prompts_by_ids: same - add error count to return tuple.
LOW
- prompt.export_single_prompt / export_related_prompts_by_name: upgrade
history-fetch failure from debug-only to always-visible warning
so users know the export is incomplete. - all._export_all_prompts: add error counter; propagate to had_errors
in export_all so the process exits with code 1 on prompt failures.
Adds 8 new unit tests in tests/unit/cli/test_export_error_handling.py
covering the three HIGH fixes.Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
- [NA] [SDK] fix: resolve mypy type error in _export_wait_duration
Use a separate local variable
parsedfor the Optional[float] header
lookups instead of reusingseconds(which is typedfloatearlier in
the same function scope), eliminating the incompatible-assignment error
mypy reported on line 110.Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
- [NA] [SDK] fix: address PR review comments on export error handling
- all.py: return (0, 0, 1) when prompt listing fails so export_all exits 1
- dataset.py: fix docstring to document 3-tuple return value
- experiment.py: add LOGGER, log non-404 API errors before re-raise
- experiment.py: propagate dataset/prompt error counts to sys.exit(1)
- prompt.py: extract _safe_prompt_history helper to remove duplication
- tests: switch TestFetchTraceDataRetry to test through public export_traces_by_ids
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
- [NA] [SDK] fix: use non-retryable status code in unexpected_api_error test
503 is in RETRYABLE_STATUS_CODES so @_export_rest_retry retried it 8 times
with exponential backoff, causing the unit test to timeout in CI after ~2 min.
Switch to 400 which is not retried and raises immediately.Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
Co-authored-by: Claude Sonnet 4.6 noreply@anthropic.com
下载附件