openrunner-sdk 2.41.3__tar.gz → 2.41.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/PKG-INFO +1 -1
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/CLAUDE.md +26 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/__init__.py +7 -1
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/_native.py +4 -1
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/datasets.py +215 -5
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/install_commands.py +42 -2
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/pyproject.toml +1 -1
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_datasets_module.py +140 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/.gitignore +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/=6.0 +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/=8.1 +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/README.md +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/_retry_transport.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/_safepath.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/_secret_rules.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/api_client.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/artifact.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/autoresearch.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/buffer.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/cache.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/cli.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/config.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/cost.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/dataset.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/environment.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/evaluation.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/feedback.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/git_info.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/api_integration.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/cost_guard.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/gpu_types.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/price_compare.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/provider_base.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/forge_provider.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/lambda_cloud.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/modal_provider.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/ovhcloud.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/runpod.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/providers/vastai.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/runner.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/gpu/workspace_sync.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/guardrails.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/handover.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/hooks/patent-lab-post-commit +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/accelerate.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/anthropic_tracer.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/catboost.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/diffusers.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/fastai.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/forced_alignment.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/gladia.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/gymnasium.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/huggingface.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/hydra.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/ignite.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/jax.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/keras.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/langchain.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/lightgbm.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/lightning.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/llamaindex.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/openai_finetune.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/openai_tracer.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/optuna.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/pytorch.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/sb3.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/sklearn.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/skypilot.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/tensorflow.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/trl.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/tts.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/ultralytics.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/voice_agent.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/whisper.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/integration/xgboost.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/launch.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/machine.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/mcp_server.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/media.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/migrate.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/model.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/model_card.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/offline.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/patent_scan.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/pii.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/plot.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/projects.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/prompt.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/query_api.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/redact.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/reload.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/research.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/research_policy.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/run.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/scorers.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/sender.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/session.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/settings.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/summary.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/sweep.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/sync.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/system_metrics.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/tensorboard.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/tools/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/tools/patent_report.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/trace.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/transcript_formatter.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/wal.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/wandb_compat/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/wandb_compat/_shim.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/openrunner/wer.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/scripts/gen_betterleaks_rules.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/conftest.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-aaa/config.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-aaa/metadata.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-aaa/metrics.jsonl +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-aaa/summary.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/artifacts/model-checkpoint/manifest.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/artifacts/model-checkpoint/weights.bin +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/artifacts/sample-image/manifest.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/artifacts/sample-image/preview.png +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/config.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/metadata.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/metrics.jsonl +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/fixtures/wandb-export-mini/run-bbb/summary.json +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/integration/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/integration/conftest.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/integration/test_artifact_round_trip.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_alert.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_aliases.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_api_client.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_api_client_methods.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_api_client_transport.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_artifact.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_buffer.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cache.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_class_scorers.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli_artifact_sweep.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli_datasets.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli_gpu_registry_deploy.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli_infra.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli_remainder.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_cli_topup.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_config.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_evaluation.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_finish.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_git_info.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/__init__.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/conftest.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_cost_guard.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_engine_serverside.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_forge.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_governed_jobs.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_gpu_cluster.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_gpu_types.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_lambda.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_modal.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_ovh_training.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_ovhcloud.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_price_compare.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_provider_base.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_runner.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_runpod.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_sdk_gpu_api.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_vastai.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu/test_workspace_sync.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_gpu_modal_creds.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_init.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_init_facade.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_install_commands.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_fastai.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_huggingface.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_keras.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_langchain.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_lightning.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_pytorch.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_setA.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_setB.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_setC.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_sklearn.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_integration_xgboost.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_launch.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_log.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_log_code.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_machine_migrate.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_mcp_decisions.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_mcp_monitor.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_mcp_predictions.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_mcp_server.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_media.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_media_extra.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_migrate.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_offline.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_offline_sync.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_patent_scan.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_pii.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_plot.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_plot_media_extra2.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_prompt_module.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_pure_modules.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_query_api.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_redact.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_reload_module.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_research_module.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_resume.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_retry_transport.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_run_module.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sdk_cluster_j1.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sdk_cluster_j2.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sdk_cluster_j3.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sdk_cluster_j4.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sdk_core_edges.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sdk_features.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sender.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_session_module.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_session_sync.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_summary.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_sweep.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_system_metrics.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_topup_hi.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_trace.py +0 -0
- {openrunner_sdk-2.41.3 → openrunner_sdk-2.41.5}/tests/test_wandb_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openrunner-sdk
|
|
3
|
-
Version: 2.41.
|
|
3
|
+
Version: 2.41.5
|
|
4
4
|
Summary: OpenRunner SDK - W&B-compatible ML experiment tracking client
|
|
5
5
|
Project-URL: Homepage, https://github.com/jqueguiner/openrunner
|
|
6
6
|
Project-URL: Repository, https://github.com/jqueguiner/openrunner
|
|
@@ -84,6 +84,32 @@ CLI: `openrunner datasets index org/name --text-col en --text-col fr`,
|
|
|
84
84
|
combined `_text` column so one query spans all text fields; preview/search read
|
|
85
85
|
the LanceDB table on the dataset's own connection.
|
|
86
86
|
|
|
87
|
+
### Search modes + query-derived datasets
|
|
88
|
+
|
|
89
|
+
Beyond FTS, the client exposes semantic / lexical search and **derivation by
|
|
90
|
+
query** — build a child dataset from a SUBSET of a parent selected by a search
|
|
91
|
+
(only matching primary keys stored; no media copied; de-dup + lineage automatic).
|
|
92
|
+
These delegate to the native Rust core (`openrunner-core` wheel) when installed,
|
|
93
|
+
falling back to pure-Python httpx otherwise:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
ord.search_dataset(repo, q, mode="mixed"|"exact", lang="fr") # BM25 / phrase, lang filter
|
|
97
|
+
ord.optimize_embedding_search(repo) # build ANN index (once)
|
|
98
|
+
ord.semantic_search(repo, q, lang="en,fr") # vector (cosine) search
|
|
99
|
+
ord.word_lookup(repo, "medical,doctor", op="union"|"intersect", lang="fr") # lexical_map
|
|
100
|
+
ord.keyword_expand("medical terms in french", count=300) # LLM -> {keywords, csv, count}
|
|
101
|
+
|
|
102
|
+
# derive: mode = word (op union/intersect) | fts | exact | semantic; lang filter; append via target_repo_id
|
|
103
|
+
child = ord.derive_by_query(parent, keywords_csv, name="org/medical-fr",
|
|
104
|
+
mode="word", lang="fr", limit=5000)
|
|
105
|
+
ord.derive_by_query(parent, "more,terms", target_repo_id="org/medical-fr", mode="word") # append, de-dup
|
|
106
|
+
ord.derived_rows("org/medical-fr", limit=50) # member keys + inherited parent fields
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`word`+`op="union"` = rows matching ANY term; `op="intersect"` (via `word_lookup`)
|
|
110
|
+
= rows matching ALL. `semantic` needs `optimize_embedding_search` first. Slash
|
|
111
|
+
command: `/openrunner:derive-dataset` (query-derivation **or** computed-column).
|
|
112
|
+
|
|
87
113
|
# OpenRunner MCP Integration
|
|
88
114
|
|
|
89
115
|
When the user publishes a MODEL, or asks to write/update a model card:
|
|
@@ -101,8 +101,14 @@ from openrunner.datasets import (
|
|
|
101
101
|
link_project,
|
|
102
102
|
load_dataset,
|
|
103
103
|
add_derivation,
|
|
104
|
+
derive_by_query,
|
|
105
|
+
derived_rows,
|
|
106
|
+
keyword_expand,
|
|
107
|
+
optimize_embedding_search,
|
|
104
108
|
push_dataset,
|
|
105
109
|
search_dataset,
|
|
110
|
+
semantic_search,
|
|
111
|
+
word_lookup,
|
|
106
112
|
set_dataset_card,
|
|
107
113
|
set_storage_policy,
|
|
108
114
|
upload_file,
|
|
@@ -181,7 +187,7 @@ launch.from_run = _launch_from_run # type: ignore[attr-defined]
|
|
|
181
187
|
# openrunner.trace.patch_openai() syntax
|
|
182
188
|
trace.patch_openai = _patch_openai # type: ignore[attr-defined]
|
|
183
189
|
|
|
184
|
-
__version__ = "2.41.
|
|
190
|
+
__version__ = "2.41.4"
|
|
185
191
|
|
|
186
192
|
logger = logging.getLogger("openrunner")
|
|
187
193
|
|
|
@@ -9,7 +9,10 @@ single-implementation point, never a hard dependency.
|
|
|
9
9
|
|
|
10
10
|
Covered surface today: projects (incl. linked repo), artifacts/versions,
|
|
11
11
|
presigned downloads (selective, GIL released during transfers), container
|
|
12
|
-
registries + broker login tokens
|
|
12
|
+
registries + broker login tokens, dataset editable-overlay columns
|
|
13
|
+
(add column / set cell / edit row / get row — source columns stay read-only),
|
|
14
|
+
and dataset search + query-derivation (full-text / semantic / word union·intersect,
|
|
15
|
+
LLM keyword-expand, derive-by-query + derived rows).
|
|
13
16
|
"""
|
|
14
17
|
|
|
15
18
|
from __future__ import annotations
|
|
@@ -194,14 +194,27 @@ class DatasetsClient:
|
|
|
194
194
|
or _g.get("base_url") or "http://localhost:8000")
|
|
195
195
|
if not key:
|
|
196
196
|
raise ValueError("API key required. Set OPENRUNNER_API_KEY, pass api_key=, or run `openrunner login`.")
|
|
197
|
+
# Raw creds kept so the optional native core (Rust) can be built lazily —
|
|
198
|
+
# the crate appends its own /api/v1, so hand it the bare base URL.
|
|
199
|
+
self._base_url = url.rstrip("/")
|
|
200
|
+
self._api_key = key
|
|
201
|
+
self._native: Any = "unset" # sentinel: native core not yet resolved
|
|
197
202
|
from ._retry_transport import RetryTransport
|
|
198
203
|
self._http = httpx.Client(
|
|
199
|
-
base_url=f"{
|
|
200
|
-
headers={"Authorization": f"Bearer {
|
|
204
|
+
base_url=f"{self._base_url}/api/v1",
|
|
205
|
+
headers={"Authorization": f"Bearer {self._api_key}"},
|
|
201
206
|
timeout=timeout,
|
|
202
207
|
transport=RetryTransport(),
|
|
203
208
|
)
|
|
204
209
|
|
|
210
|
+
def _native_client(self):
|
|
211
|
+
"""The native (Rust/PyO3) client if the ``openrunner-core`` wheel is
|
|
212
|
+
installed, else ``None`` — an accelerator with a pure-Python fallback."""
|
|
213
|
+
if self._native == "unset":
|
|
214
|
+
from openrunner import _native
|
|
215
|
+
self._native = _native.native_client(self._base_url, self._api_key)
|
|
216
|
+
return self._native
|
|
217
|
+
|
|
205
218
|
# -- resolution ----------------------------------------------------------
|
|
206
219
|
def _org_id(self, org: str) -> str:
|
|
207
220
|
r = self._http.get("/organizations")
|
|
@@ -733,13 +746,168 @@ class DatasetsClient:
|
|
|
733
746
|
_check(r)
|
|
734
747
|
return r.json()
|
|
735
748
|
|
|
736
|
-
def search_dataset(
|
|
737
|
-
|
|
749
|
+
def search_dataset(
|
|
750
|
+
self,
|
|
751
|
+
repo_id: str,
|
|
752
|
+
query: str,
|
|
753
|
+
*,
|
|
754
|
+
limit: int = 20,
|
|
755
|
+
mode: str = "mixed",
|
|
756
|
+
lang: str = "",
|
|
757
|
+
) -> list[dict]:
|
|
758
|
+
"""Full-text search a dataset's index. Call ``index_dataset`` first.
|
|
759
|
+
|
|
760
|
+
``mode``: "mixed" (ranked tokens, default) or "exact" (phrase match).
|
|
761
|
+
``lang``: restrict to a language / CSV ("fr" or "fr,en"); "" = all.
|
|
762
|
+
Delegates to the native (Rust) core when the ``openrunner-core`` wheel is
|
|
763
|
+
installed, else pure-Python httpx.
|
|
764
|
+
"""
|
|
738
765
|
ds = self._resolve(repo_id)
|
|
739
|
-
|
|
766
|
+
nat = self._native_client()
|
|
767
|
+
if nat is not None:
|
|
768
|
+
return nat.dataset_search(str(ds.id), query, mode, lang, limit).get("rows", [])
|
|
769
|
+
params: dict[str, Any] = {"q": query, "limit": limit, "mode": mode}
|
|
770
|
+
if lang:
|
|
771
|
+
params["lang"] = lang
|
|
772
|
+
r = self._http.get(f"/datasets/{ds.id}/search", params=params)
|
|
740
773
|
_check(r)
|
|
741
774
|
return r.json().get("rows", [])
|
|
742
775
|
|
|
776
|
+
# -- semantic / lexical / query-derivation -------------------------------
|
|
777
|
+
def semantic_search(
|
|
778
|
+
self, repo_id: str, query: str, *, limit: int = 20, lang: str = ""
|
|
779
|
+
) -> list[dict]:
|
|
780
|
+
"""Vector (cosine ANN) search over a dataset's embeddings.
|
|
781
|
+
|
|
782
|
+
Requires the embedding index built first via
|
|
783
|
+
``optimize_embedding_search``. Native core when available, else httpx.
|
|
784
|
+
"""
|
|
785
|
+
ds = self._resolve(repo_id)
|
|
786
|
+
nat = self._native_client()
|
|
787
|
+
if nat is not None:
|
|
788
|
+
out = nat.semantic_search(str(ds.id), query, lang, limit)
|
|
789
|
+
return out.get("rows", out.get("hits", []))
|
|
790
|
+
params: dict[str, Any] = {"q": query, "limit": limit}
|
|
791
|
+
if lang:
|
|
792
|
+
params["lang"] = lang
|
|
793
|
+
r = self._http.get(f"/datasets/{ds.id}/semantic", params=params)
|
|
794
|
+
_check(r)
|
|
795
|
+
return r.json().get("rows", r.json().get("hits", []))
|
|
796
|
+
|
|
797
|
+
def optimize_embedding_search(
|
|
798
|
+
self,
|
|
799
|
+
repo_id: str,
|
|
800
|
+
*,
|
|
801
|
+
text_column: str | None = None,
|
|
802
|
+
max_rows: int = 200000,
|
|
803
|
+
model: str | None = None,
|
|
804
|
+
) -> dict:
|
|
805
|
+
"""Embed missing rows and build the ANN index that ``semantic_search``
|
|
806
|
+
(and derive ``mode="semantic"``) need. Native core when available."""
|
|
807
|
+
ds = self._resolve(repo_id)
|
|
808
|
+
nat = self._native_client()
|
|
809
|
+
if nat is not None:
|
|
810
|
+
return nat.optimize_embedding_search(str(ds.id), text_column, max_rows, model)
|
|
811
|
+
body = {"text_column": text_column, "max_rows": max_rows, "model": model}
|
|
812
|
+
r = self._http.post(
|
|
813
|
+
f"/datasets/{ds.id}/optimize-embedding-search", json=body, timeout=1800.0
|
|
814
|
+
)
|
|
815
|
+
_check(r)
|
|
816
|
+
return r.json()
|
|
817
|
+
|
|
818
|
+
def word_lookup(
|
|
819
|
+
self, repo_id: str, terms: str | list[str], *, op: str = "union", lang: str = ""
|
|
820
|
+
) -> dict:
|
|
821
|
+
"""Word(s) -> matching-row lookup via the ``lexical_map`` table.
|
|
822
|
+
|
|
823
|
+
``terms`` is one word, a CSV string, or a list. ``op`` combines
|
|
824
|
+
multi-term hits: "union" (ANY) or "intersect" (ALL). ``lang`` scopes to a
|
|
825
|
+
language / CSV. Returns per-term df + combined ids. Native core when
|
|
826
|
+
available, else httpx.
|
|
827
|
+
"""
|
|
828
|
+
ds = self._resolve(repo_id)
|
|
829
|
+
term = ",".join(terms) if isinstance(terms, (list, tuple)) else terms
|
|
830
|
+
nat = self._native_client()
|
|
831
|
+
if nat is not None:
|
|
832
|
+
return nat.word_lookup(str(ds.id), term, op, lang)
|
|
833
|
+
params: dict[str, Any] = {"term": term, "op": op}
|
|
834
|
+
if lang:
|
|
835
|
+
params["lang"] = lang
|
|
836
|
+
r = self._http.get(f"/datasets/{ds.id}/word-lookup", params=params)
|
|
837
|
+
_check(r)
|
|
838
|
+
return r.json()
|
|
839
|
+
|
|
840
|
+
def keyword_expand(
|
|
841
|
+
self, prompt: str, *, count: int = 500, model: str | None = None
|
|
842
|
+
) -> dict:
|
|
843
|
+
"""Expand a domain prompt into many search keywords via an LLM.
|
|
844
|
+
|
|
845
|
+
Returns ``{keywords, csv, count, model, prompt}`` — feed ``csv`` into
|
|
846
|
+
``word_lookup`` or ``derive_by_query(mode="word", q=csv)``. Native core
|
|
847
|
+
when available, else httpx.
|
|
848
|
+
"""
|
|
849
|
+
nat = self._native_client()
|
|
850
|
+
if nat is not None:
|
|
851
|
+
return nat.keyword_expand(prompt, count, model)
|
|
852
|
+
body = {"prompt": prompt, "count": count, "model": model}
|
|
853
|
+
r = self._http.post("/datasets/keyword-expand", json=body, timeout=120.0)
|
|
854
|
+
_check(r)
|
|
855
|
+
return r.json()
|
|
856
|
+
|
|
857
|
+
def derive_by_query(
|
|
858
|
+
self,
|
|
859
|
+
repo_id: str,
|
|
860
|
+
q: str,
|
|
861
|
+
*,
|
|
862
|
+
name: str | None = None,
|
|
863
|
+
mode: str = "semantic",
|
|
864
|
+
lang: str | None = None,
|
|
865
|
+
limit: int = 2000,
|
|
866
|
+
target_repo_id: str | None = None,
|
|
867
|
+
project_id: str | None = None,
|
|
868
|
+
) -> DatasetInfo:
|
|
869
|
+
"""Create (or append to) a dataset **derived from a query** over ``repo_id``.
|
|
870
|
+
|
|
871
|
+
``mode``: "word" (``q`` = term / CSV; pairs with LLM ``keyword_expand``),
|
|
872
|
+
"fts" (BM25), "exact" (phrase), "semantic" (vector — needs
|
|
873
|
+
``optimize_embedding_search``). ``lang`` filters by language / CSV. Pass
|
|
874
|
+
``name`` to create, or ``target_repo_id`` to append (must derive from the
|
|
875
|
+
same parent). Lineage is recorded automatically. The query runs and
|
|
876
|
+
member keys are recorded natively when the core wheel is installed; the
|
|
877
|
+
parent/target resolution + DatasetInfo wrapping stay in Python.
|
|
878
|
+
"""
|
|
879
|
+
ds = self._resolve(repo_id)
|
|
880
|
+
body: dict[str, Any] = {"mode": mode, "q": q, "limit": limit}
|
|
881
|
+
if name:
|
|
882
|
+
body["name"] = name
|
|
883
|
+
if lang:
|
|
884
|
+
body["lang"] = lang
|
|
885
|
+
if project_id:
|
|
886
|
+
body["project_id"] = str(project_id)
|
|
887
|
+
if target_repo_id:
|
|
888
|
+
body["target_dataset_id"] = str(self._resolve(target_repo_id).id)
|
|
889
|
+
elif not name:
|
|
890
|
+
raise ValueError("derive_by_query needs either name= (create) or target_repo_id= (append)")
|
|
891
|
+
nat = self._native_client()
|
|
892
|
+
if nat is not None:
|
|
893
|
+
return DatasetInfo._from_json(nat.derive_dataset(str(ds.id), body))
|
|
894
|
+
r = self._http.post(f"/datasets/{ds.id}/derive", json=body, timeout=600.0)
|
|
895
|
+
_check(r)
|
|
896
|
+
return DatasetInfo._from_json(r.json())
|
|
897
|
+
|
|
898
|
+
def derived_rows(self, repo_id: str, *, limit: int = 50, offset: int = 0) -> dict:
|
|
899
|
+
"""Page a query-derived dataset's rows: member keys + inherited parent
|
|
900
|
+
fields (lineage-namespaced) + extra columns. Native core when available."""
|
|
901
|
+
ds = self._resolve(repo_id)
|
|
902
|
+
nat = self._native_client()
|
|
903
|
+
if nat is not None:
|
|
904
|
+
return nat.derived_rows(str(ds.id), limit, offset)
|
|
905
|
+
r = self._http.get(
|
|
906
|
+
f"/datasets/{ds.id}/derived-rows", params={"limit": limit, "offset": offset}
|
|
907
|
+
)
|
|
908
|
+
_check(r)
|
|
909
|
+
return r.json()
|
|
910
|
+
|
|
743
911
|
def update_dataset(self, repo_id: str, **fields: Any) -> DatasetInfo:
|
|
744
912
|
ds = self._resolve(repo_id)
|
|
745
913
|
if "card" in fields:
|
|
@@ -812,6 +980,9 @@ class DatasetsClient:
|
|
|
812
980
|
rejected. Returns the editable column names.
|
|
813
981
|
"""
|
|
814
982
|
ds = self._resolve(repo_id)
|
|
983
|
+
nat = self._native_client()
|
|
984
|
+
if nat is not None:
|
|
985
|
+
return nat.add_dataset_column(str(ds.id), name, default)
|
|
815
986
|
r = self._http.post(f"/datasets/{ds.id}/columns",
|
|
816
987
|
json={"name": name, "default": default})
|
|
817
988
|
_check(r)
|
|
@@ -826,6 +997,9 @@ class DatasetsClient:
|
|
|
826
997
|
``{ok, debug_id, column}``.
|
|
827
998
|
"""
|
|
828
999
|
ds = self._resolve(repo_id)
|
|
1000
|
+
nat = self._native_client()
|
|
1001
|
+
if nat is not None:
|
|
1002
|
+
return nat.set_dataset_cell(str(ds.id), debug_id, column, value)
|
|
829
1003
|
r = self._http.patch(f"/datasets/{ds.id}/cell",
|
|
830
1004
|
json={"debug_id": debug_id, "column": column, "value": value})
|
|
831
1005
|
_check(r)
|
|
@@ -839,6 +1013,9 @@ class DatasetsClient:
|
|
|
839
1013
|
a read-only source column. Returns ``{ok, debug_id, columns}``.
|
|
840
1014
|
"""
|
|
841
1015
|
ds = self._resolve(repo_id)
|
|
1016
|
+
nat = self._native_client()
|
|
1017
|
+
if nat is not None:
|
|
1018
|
+
return nat.edit_dataset_row(str(ds.id), debug_id, values)
|
|
842
1019
|
r = self._http.patch(f"/datasets/{ds.id}/rows/{debug_id}", json={"values": values})
|
|
843
1020
|
_check(r)
|
|
844
1021
|
return r.json()
|
|
@@ -849,6 +1026,9 @@ class DatasetsClient:
|
|
|
849
1026
|
``{debug_id, row, editable_columns}`` (everything in ``row`` not listed in
|
|
850
1027
|
``editable_columns`` is a read-only parent column)."""
|
|
851
1028
|
ds = self._resolve(repo_id)
|
|
1029
|
+
nat = self._native_client()
|
|
1030
|
+
if nat is not None:
|
|
1031
|
+
return nat.get_dataset_row(str(ds.id), debug_id)
|
|
852
1032
|
r = self._http.get(f"/datasets/{ds.id}/row", params={"debug_id": debug_id})
|
|
853
1033
|
_check(r)
|
|
854
1034
|
return r.json()
|
|
@@ -1107,6 +1287,36 @@ def search_dataset(repo_id: str, query: str, **kwargs: Any) -> list[dict]:
|
|
|
1107
1287
|
return _c().search_dataset(repo_id, query, **kwargs)
|
|
1108
1288
|
|
|
1109
1289
|
|
|
1290
|
+
def semantic_search(repo_id: str, query: str, **kwargs: Any) -> list[dict]:
|
|
1291
|
+
"""Vector (cosine ANN) search — needs ``optimize_embedding_search`` first."""
|
|
1292
|
+
return _c().semantic_search(repo_id, query, **kwargs)
|
|
1293
|
+
|
|
1294
|
+
|
|
1295
|
+
def optimize_embedding_search(repo_id: str, **kwargs: Any) -> dict:
|
|
1296
|
+
"""Embed rows + build the ANN index for semantic search / semantic-derive."""
|
|
1297
|
+
return _c().optimize_embedding_search(repo_id, **kwargs)
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
def word_lookup(repo_id: str, terms: "str | list[str]", **kwargs: Any) -> dict:
|
|
1301
|
+
"""Word(s) -> rows via lexical_map; ``op`` union|intersect, ``lang`` filter."""
|
|
1302
|
+
return _c().word_lookup(repo_id, terms, **kwargs)
|
|
1303
|
+
|
|
1304
|
+
|
|
1305
|
+
def keyword_expand(prompt: str, **kwargs: Any) -> dict:
|
|
1306
|
+
"""LLM-expand a domain prompt into search keywords ({keywords, csv, count})."""
|
|
1307
|
+
return _c().keyword_expand(prompt, **kwargs)
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
def derive_by_query(repo_id: str, q: str, **kwargs: Any) -> "DatasetInfo":
|
|
1311
|
+
"""Create/append a dataset derived from a word|fts|exact|semantic query."""
|
|
1312
|
+
return _c().derive_by_query(repo_id, q, **kwargs)
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
def derived_rows(repo_id: str, **kwargs: Any) -> dict:
|
|
1316
|
+
"""Page a query-derived dataset's rows (member keys + inherited parent fields)."""
|
|
1317
|
+
return _c().derived_rows(repo_id, **kwargs)
|
|
1318
|
+
|
|
1319
|
+
|
|
1110
1320
|
def set_storage_policy(repo_id: str, tier: str) -> dict:
|
|
1111
1321
|
return _c().set_storage_policy(repo_id, tier)
|
|
1112
1322
|
|
|
@@ -2135,14 +2135,54 @@ Give the dataset **URL** (`<base>/datasets/<id>`), the modality/tasks/languages,
|
|
|
2135
2135
|
|
|
2136
2136
|
DERIVE_DATASET_CMD = """---
|
|
2137
2137
|
name: {prefix}derive-dataset
|
|
2138
|
-
description: Derive a dataset from an existing one by
|
|
2139
|
-
argument-hint: "[parent org/name] [child org/name] [--column NAME]"
|
|
2138
|
+
description: Derive a dataset from an existing one — either by a SEARCH QUERY (semantic / word union·intersect / fts / exact, with language filter + LLM keyword expansion) or by adding a computed column. Keeps lineage, never re-uploads the parent's media.
|
|
2139
|
+
argument-hint: "[parent org/name] [child org/name] [--query ... | --column NAME]"
|
|
2140
2140
|
allowed-tools:
|
|
2141
2141
|
- Bash
|
|
2142
2142
|
- Read
|
|
2143
2143
|
- AskUserQuestion
|
|
2144
2144
|
---
|
|
2145
2145
|
|
|
2146
|
+
Two ways to derive a NEW dataset from a parent, both lineage-tracked and media-free:
|
|
2147
|
+
|
|
2148
|
+
- **A. Query-derivation** — select a SUBSET of the parent's rows by a search: `semantic`, `word` (term list, UNION or INTERSECT), `fts` (BM25), or `exact` (phrase), with an optional **language filter** and optional **LLM keyword expansion**. Only matching primary keys are stored — no rows/media copied, de-dup automatic. Use when the user says "make a dataset of the medical/french/... clips", "everything matching X", "semantically similar to X".
|
|
2149
|
+
- **B. Computed-column** — add one or more computed columns (e.g. a heuristic `suspicious` GT-quality flag) keyed 1:1 to the parent rows.
|
|
2150
|
+
|
|
2151
|
+
Pick by intent: **subset/select rows -> A**; **annotate/flag rows -> B**.
|
|
2152
|
+
|
|
2153
|
+
---
|
|
2154
|
+
|
|
2155
|
+
## A. Query-derivation (semantic / word union·intersect / fts / exact + lang + LLM keywords)
|
|
2156
|
+
|
|
2157
|
+
All server-side; the SDK delegates to the native Rust core when installed. `PARENT` must be indexed (`ds.index_dataset(...)`; for `semantic`, also `ds.optimize_embedding_search(...)`).
|
|
2158
|
+
|
|
2159
|
+
```bash
|
|
2160
|
+
python3 -c "
|
|
2161
|
+
from openrunner import datasets as ds
|
|
2162
|
+
|
|
2163
|
+
kw = ds.keyword_expand('medical terms in french', count=300) # {{keywords, csv, count}}
|
|
2164
|
+
child = ds.derive_by_query('ORG/PARENT', kw['csv'],
|
|
2165
|
+
name='ORG/medical-fr', mode='word', lang='fr', limit=5000) # WORD union + lang filter
|
|
2166
|
+
print('created', child.name, child.id)
|
|
2167
|
+
|
|
2168
|
+
hit = ds.word_lookup('ORG/PARENT', 'medical,doctor,prescription', op='intersect', lang='fr') # ALL terms
|
|
2169
|
+
|
|
2170
|
+
ds.optimize_embedding_search('ORG/PARENT') # build ANN index once
|
|
2171
|
+
ds.derive_by_query('ORG/PARENT', 'patient describing symptoms',
|
|
2172
|
+
name='ORG/symptom-desc', mode='semantic', lang='en,fr') # SEMANTIC
|
|
2173
|
+
|
|
2174
|
+
ds.derive_by_query('ORG/PARENT', 'insurance claim', name='ORG/claims', mode='fts') # BM25
|
|
2175
|
+
ds.derive_by_query('ORG/PARENT', 'pharmacy,pharmacist', target_repo_id='ORG/medical-fr', mode='word') # append, de-dup
|
|
2176
|
+
print(ds.derived_rows('ORG/medical-fr', limit=10))
|
|
2177
|
+
"
|
|
2178
|
+
```
|
|
2179
|
+
|
|
2180
|
+
Query modes (`mode=`): `word` (CSV of terms; `op='union'|'intersect'`), `fts` (BM25), `exact` (phrase), `semantic` (vector ANN). `lang=` takes a language or CSV ("fr" / "en,fr"); "" = all. Lineage to `PARENT` is recorded automatically by `derive_by_query`.
|
|
2181
|
+
|
|
2182
|
+
---
|
|
2183
|
+
|
|
2184
|
+
## B. Computed-column derivation
|
|
2185
|
+
|
|
2146
2186
|
Derive a NEW dataset from an existing parent by adding one or more **computed columns** (e.g. a heuristic `suspicious` GT-quality flag), preserving lineage.
|
|
2147
2187
|
|
|
2148
2188
|
**Datasets are first-class — do NOT use `openrunner.Artifact` for this.** An Artifact is a model/file blob attached to a run; a dataset is a governed, queryable, lineage-tracked entity. Deriving = a child dataset linked to its parent via `add_derivation`, so the platform shows the lineage graph and **blocks deleting the parent while children exist**.
|
|
@@ -684,11 +684,121 @@ def test_index_dataset_truncated_warns(monkeypatch):
|
|
|
684
684
|
|
|
685
685
|
def test_search_dataset(monkeypatch):
|
|
686
686
|
c = _client(monkeypatch)
|
|
687
|
+
c._native = None # force httpx fallback (no native wheel)
|
|
687
688
|
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
688
689
|
c._http.get.return_value = _resp(200, {"rows": [{"id": 1}]})
|
|
689
690
|
assert c.search_dataset("gladia/wmt", "hi") == [{"id": 1}]
|
|
690
691
|
|
|
691
692
|
|
|
693
|
+
def test_search_dataset_mode_and_lang(monkeypatch):
|
|
694
|
+
c = _client(monkeypatch)
|
|
695
|
+
c._native = None
|
|
696
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
697
|
+
c._http.get.return_value = _resp(200, {"rows": []})
|
|
698
|
+
c.search_dataset("g/n", "hi", mode="exact", lang="fr")
|
|
699
|
+
params = c._http.get.call_args.kwargs["params"]
|
|
700
|
+
assert params["mode"] == "exact" and params["lang"] == "fr"
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
def test_search_dataset_native_delegates(monkeypatch):
|
|
704
|
+
c = _client(monkeypatch)
|
|
705
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
706
|
+
nat = MagicMock()
|
|
707
|
+
nat.dataset_search.return_value = {"rows": [{"id": 42}]}
|
|
708
|
+
c._native = nat
|
|
709
|
+
assert c.search_dataset("g/n", "hi", mode="exact", lang="fr", limit=5) == [{"id": 42}]
|
|
710
|
+
nat.dataset_search.assert_called_once_with("ds-1", "hi", "exact", "fr", 5)
|
|
711
|
+
c._http.get.assert_not_called()
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
def test_semantic_search(monkeypatch):
|
|
715
|
+
c = _client(monkeypatch)
|
|
716
|
+
c._native = None
|
|
717
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
718
|
+
c._http.get.return_value = _resp(200, {"hits": [{"id": 9, "score": 0.8}]})
|
|
719
|
+
assert c.semantic_search("g/n", "symptoms", lang="en,fr")[0]["id"] == 9
|
|
720
|
+
assert "/semantic" in c._http.get.call_args.args[0]
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def test_optimize_embedding_search(monkeypatch):
|
|
724
|
+
c = _client(monkeypatch)
|
|
725
|
+
c._native = None
|
|
726
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
727
|
+
c._http.post.return_value = _resp(200, {"status": "running"})
|
|
728
|
+
assert c.optimize_embedding_search("g/n")["status"] == "running"
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
def test_word_lookup_union_intersect(monkeypatch):
|
|
732
|
+
c = _client(monkeypatch)
|
|
733
|
+
c._native = None
|
|
734
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
735
|
+
c._http.get.return_value = _resp(200, {"ids": [1, 2]})
|
|
736
|
+
c.word_lookup("g/n", ["a", "b"], op="intersect", lang="fr")
|
|
737
|
+
params = c._http.get.call_args.kwargs["params"]
|
|
738
|
+
assert params["term"] == "a,b" and params["op"] == "intersect" and params["lang"] == "fr"
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
def test_keyword_expand(monkeypatch):
|
|
742
|
+
c = _client(monkeypatch)
|
|
743
|
+
c._native = None
|
|
744
|
+
c._http.post.return_value = _resp(200, {"keywords": ["a", "b"], "csv": "a, b", "count": 2})
|
|
745
|
+
out = c.keyword_expand("medical terms in french", count=2)
|
|
746
|
+
assert out["count"] == 2
|
|
747
|
+
assert c._http.post.call_args.args[0] == "/datasets/keyword-expand"
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
def test_derive_by_query_create(monkeypatch):
|
|
751
|
+
c = _client(monkeypatch)
|
|
752
|
+
c._native = None
|
|
753
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
754
|
+
c._http.post.return_value = _resp(200, dict(_DS_JSON, name="medical-fr"))
|
|
755
|
+
out = c.derive_by_query("g/parent", "a,b", name="g/medical-fr", mode="word", lang="fr")
|
|
756
|
+
assert out.name == "medical-fr"
|
|
757
|
+
body = c._http.post.call_args.kwargs["json"]
|
|
758
|
+
assert body["mode"] == "word" and body["name"] == "g/medical-fr" and body["lang"] == "fr"
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
def test_derive_by_query_native_delegates(monkeypatch):
|
|
762
|
+
c = _client(monkeypatch)
|
|
763
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
764
|
+
nat = MagicMock()
|
|
765
|
+
nat.derive_dataset.return_value = dict(_DS_JSON, name="medical-fr")
|
|
766
|
+
c._native = nat
|
|
767
|
+
out = c.derive_by_query("g/parent", "a,b", name="g/medical-fr", mode="word")
|
|
768
|
+
assert out.name == "medical-fr"
|
|
769
|
+
nat.derive_dataset.assert_called_once()
|
|
770
|
+
c._http.post.assert_not_called()
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
def test_derive_by_query_append(monkeypatch):
|
|
774
|
+
c = _client(monkeypatch)
|
|
775
|
+
c._native = None
|
|
776
|
+
parent = DatasetInfo._from_json(_DS_JSON)
|
|
777
|
+
target = DatasetInfo._from_json(dict(_DS_JSON, id="ds-2", name="medical-fr"))
|
|
778
|
+
c._resolve = MagicMock(side_effect=[parent, target])
|
|
779
|
+
c._http.post.return_value = _resp(200, dict(_DS_JSON, id="ds-2"))
|
|
780
|
+
c.derive_by_query("g/parent", "c,d", target_repo_id="g/medical-fr", mode="word")
|
|
781
|
+
body = c._http.post.call_args.kwargs["json"]
|
|
782
|
+
assert body["target_dataset_id"] == "ds-2" and "name" not in body
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def test_derive_by_query_requires_name_or_target(monkeypatch):
|
|
786
|
+
c = _client(monkeypatch)
|
|
787
|
+
c._native = None
|
|
788
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
789
|
+
with pytest.raises(ValueError, match="name= .* target_repo_id="):
|
|
790
|
+
c.derive_by_query("g/parent", "q", mode="word")
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
def test_derived_rows(monkeypatch):
|
|
794
|
+
c = _client(monkeypatch)
|
|
795
|
+
c._native = None
|
|
796
|
+
c._resolve = MagicMock(return_value=DatasetInfo._from_json(_DS_JSON))
|
|
797
|
+
c._http.get.return_value = _resp(200, {"rows": [{"k": 1}], "total": 1, "offset": 0, "limit": 50})
|
|
798
|
+
assert c.derived_rows("g/n")["total"] == 1
|
|
799
|
+
assert "/derived-rows" in c._http.get.call_args.args[0]
|
|
800
|
+
|
|
801
|
+
|
|
692
802
|
# ===========================================================================
|
|
693
803
|
# update / card / preview / links / derivation / delete
|
|
694
804
|
# ===========================================================================
|
|
@@ -978,6 +1088,36 @@ def test_module_link_project(fake_singleton):
|
|
|
978
1088
|
assert ds_mod.link_project("g/n", "proj-1") == "P"
|
|
979
1089
|
|
|
980
1090
|
|
|
1091
|
+
def test_module_semantic_search(fake_singleton):
|
|
1092
|
+
fake_singleton.semantic_search.return_value = [{"id": 2}]
|
|
1093
|
+
assert ds_mod.semantic_search("g/n", "q", lang="fr") == [{"id": 2}]
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
def test_module_optimize_embedding_search(fake_singleton):
|
|
1097
|
+
fake_singleton.optimize_embedding_search.return_value = {"status": "ready"}
|
|
1098
|
+
assert ds_mod.optimize_embedding_search("g/n") == {"status": "ready"}
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
def test_module_word_lookup(fake_singleton):
|
|
1102
|
+
fake_singleton.word_lookup.return_value = {"ids": [1]}
|
|
1103
|
+
assert ds_mod.word_lookup("g/n", "a,b", op="union") == {"ids": [1]}
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
def test_module_keyword_expand(fake_singleton):
|
|
1107
|
+
fake_singleton.keyword_expand.return_value = {"csv": "a, b", "count": 2}
|
|
1108
|
+
assert ds_mod.keyword_expand("prompt", count=2)["count"] == 2
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
def test_module_derive_by_query(fake_singleton):
|
|
1112
|
+
fake_singleton.derive_by_query.return_value = DatasetInfo._from_json(_DS_JSON)
|
|
1113
|
+
assert ds_mod.derive_by_query("g/p", "q", name="g/c").name == "wmt"
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
def test_module_derived_rows(fake_singleton):
|
|
1117
|
+
fake_singleton.derived_rows.return_value = {"total": 3}
|
|
1118
|
+
assert ds_mod.derived_rows("g/c")["total"] == 3
|
|
1119
|
+
|
|
1120
|
+
|
|
981
1121
|
def test_module_upload_file(fake_singleton):
|
|
982
1122
|
fake_singleton.upload_file.return_value = {"ok": True}
|
|
983
1123
|
assert ds_mod.upload_file("g/n", "f.txt") == {"ok": True}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|