Files
wehub-resource-sync 5a558eb09e
Backend Tests / discover-tests (push) Waiting to run
Backend Tests / ${{ matrix.name }} (push) Blocked by required conditions
Build and Publish SDK / build-and-publish (push) Waiting to run
Build Opik Docker Images / set-version (push) Waiting to run
Build Opik Docker Images / build-backend (push) Blocked by required conditions
Build Opik Docker Images / build-sandbox-executor-python (push) Blocked by required conditions
Build Opik Docker Images / build-python-backend (push) Blocked by required conditions
Build Opik Docker Images / build-frontend (push) Blocked by required conditions
Build Opik Docker Images / create-git-tag (push) Blocked by required conditions
ClickHouse Migration Cluster Check / validate-clickhouse-migrations (push) Waiting to run
Docs - Publish / run (push) Waiting to run
E2E Tests - Post Merge (v2) / 🧪 E2E v2 Tests (${{ github.event.inputs.tier || 't1' }}) (push) Waiting to run
E2E Tests - Post Merge (v2) / 📢 Slack Notification (push) Blocked by required conditions
Frontend Unit Tests / Test on Node 20 (push) Waiting to run
Guardrails E2E Tests / Select Python version matrix (push) Waiting to run
Guardrails E2E Tests / Guardrails E2E Tests ${{matrix.python_version}} (push) Blocked by required conditions
Guardrails E2E Tests / 📢 Slack Notification (push) Blocked by required conditions
Guardrails Backend Unit Tests / Guardrails Backend Unit Tests (push) Waiting to run
Guardrails Backend Unit Tests / 📢 Slack Notification (push) Blocked by required conditions
SDK Library Integration Tests Runner / Check Secrets (push) Waiting to run
SDK Library Integration Tests Runner / Missed OpenAI API Key Warning (push) Blocked by required conditions
SDK Library Integration Tests Runner / Build (push) Blocked by required conditions
SDK Library Integration Tests Runner / openai_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / langchain_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / langchain_legacy_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / llama_index_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / anthropic_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / mistral_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / groq_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / aisuite_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / haystack_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / dspy_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / crewai_v0_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / crewai_v1_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / genai_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / adk_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / adk_legacy_1_3_0_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / evaluation_metrics_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / bedrock_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / litellm_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / harbor_tests (push) Blocked by required conditions
SDK Library Integration Tests Runner / Slack Notification (push) Blocked by required conditions
Lint Opik Helm Chart / lint-helm-chart (Helm v3.21.0) (push) Waiting to run
Lint Opik Helm Chart / lint-helm-chart (Helm v4.2.0) (push) Waiting to run
Lint Opik Helm Chart / unittest-helm-chart (push) Waiting to run
Lint Opik Helm Chart / render-equality (push) Waiting to run
Opik Optimizer - Unit Tests / Opik Optimizer Unit Tests Python ${{matrix.python_version}} (push) Waiting to run
Python BE E2E Tests / Python BE E2E (push) Waiting to run
Python Backend Tests / run-python-backend-tests (push) Waiting to run
Python SDK Unit Tests / Python SDK Unit Tests ${{matrix.python_version}} (push) Waiting to run
Release Drafter / update_release_draft (push) Waiting to run
SDK E2E Libraries Integration Tests / Check Secrets (push) Waiting to run
SDK E2E Libraries Integration Tests / Missed OpenAI API Key Warning (push) Blocked by required conditions
SDK E2E Libraries Integration Tests / build-opik (push) Blocked by required conditions
SDK E2E Libraries Integration Tests / E2E Lib Integration Python ${{matrix.python_version}} (push) Blocked by required conditions
TypeScript SDK Integration Build & Publish / build-and-publish (opik-gemini) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-langchain) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-openai) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-otel) (push) Waiting to run
TypeScript SDK Integration Build & Publish / build-and-publish (opik-vercel) (push) Waiting to run
TypeScript SDK Library Integration Tests / Check Secrets (push) Waiting to run
TypeScript SDK Library Integration Tests / opik-vercel (Vercel AI SDK / eve) (push) Blocked by required conditions
TypeScript SDK Build & Publish / build-and-publish (push) Waiting to run
TypeScript SDK Unit Tests / Test on Node ${{ matrix.node-version }} (push) Waiting to run
TypeScript SDK Compatibility V1.x E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / TypeScript SDK Compatibility V1.x E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
TypeScript SDK E2E Tests / TypeScript SDK E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
Python SDK E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK E2E Tests / Python SDK E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK E2E Tests / build-opik (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Python SDK Compatibility V1.x E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK E2E Tests / build-opik (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer E2E Tests Python ${{matrix.python_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer Integration Smoke Tests (push) Has been cancelled
🐙 Code Quality / detect (push) Has been cancelled
🐙 Code Quality / lint (${{ matrix.leg.name }}) (push) Has been cancelled
🐙 Code Quality / summary (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:25:44 +08:00

164 lines
6.4 KiB
Python

import importlib.util
import inspect
import json
import sys
import traceback
import types
import uuid
from sys import argv
from typing import Type, Union, List, Any
# ---------------------------------------------------------------------------
# Lightweight import patching
# ---------------------------------------------------------------------------
# The full `opik` package takes ~2.5s to import (pydantic_settings, REST
# client, sentry, logfire, 40+ metric classes). Under CPU contention in the
# sandbox pods this alone can exhaust the 9s execution timeout.
#
# The `_opik` package provides pure-stdlib BaseMetric and ScoreResult (~8ms).
# We register stub modules in sys.modules so that user code doing
# `from opik.evaluation.metrics import BaseMetric`
# resolves to the lightweight versions without triggering the real `opik`
# init. Any other usage — attribute access (`opik.Client`) or submodule
# imports (`from opik.evaluation.metrics.conversation import X`) — falls
# back to loading the real `opik` package. Python's import machinery
# resolves dotted submodule paths via the parent's `__path__` and
# `sys.meta_path` finders, not via `__getattr__`, so a single stub class
# plays both roles: a `ModuleType` for attribute access, and a
# `find_spec` finder on `sys.meta_path` for submodule resolution. Both
# routes funnel through `_load_real_opik`, which evicts the stubs from
# `sys.modules` and `sys.meta_path` and runs `import opik` exactly once.
# ---------------------------------------------------------------------------
import _opik._base_metric
import _opik._score_result
_stubs: dict = {}
def _load_real_opik() -> None:
"""Evict all stubs and trigger the real `opik` package init (idempotent)."""
if not _stubs:
return
for name, stub in _stubs.items():
if sys.modules.get(name) is stub:
del sys.modules[name]
if stub in sys.meta_path:
sys.meta_path.remove(stub)
_stubs.clear()
import opik # noqa: F401,F811 — triggers the real init
class _FallbackModule(types.ModuleType):
"""Stub module that lazy-loads the real `opik` package on first use.
Handles both fallback routes with one class:
- ``__getattr__`` — covers attribute access on the stub
(``from opik import Client``).
- ``find_spec`` — covers submodule imports that the installed stubs
don't satisfy (``from opik.evaluation.metrics.conversation import X``).
Python consults ``sys.meta_path`` for dotted-path resolution, not
the parent module's ``__getattr__``, so the stub registers itself
as a meta-path finder as well.
Both routes delegate to ``_load_real_opik``, after which the stub is
out of ``sys.modules`` and ``sys.meta_path`` and the standard import
machinery takes over with the real ``opik`` package.
"""
def __getattr__(self, name: str) -> Any:
_load_real_opik()
return getattr(sys.modules[self.__name__], name)
def find_spec(self, fullname: str, path, target=None):
if not _stubs or not (fullname == "opik" or fullname.startswith("opik.")):
return None
_load_real_opik()
return importlib.util.find_spec(fullname)
for _name in ["opik", "opik.evaluation", "opik.evaluation.metrics"]:
_stub = _FallbackModule(_name)
_stub.__path__ = [] # type: ignore[attr-defined]
sys.modules[_name] = _stub
_stubs[_name] = _stub
# One instance serves all `opik.*` submodule lookups — any stub will do.
sys.meta_path.insert(0, _stubs["opik"])
sys.modules["opik.evaluation.metrics.base_metric"] = _opik._base_metric
sys.modules["opik.evaluation.metrics.score_result"] = _opik._score_result
_stubs["opik.evaluation.metrics.base_metric"] = _opik._base_metric
_stubs["opik.evaluation.metrics.score_result"] = _opik._score_result
sys.modules["opik.evaluation.metrics"].base_metric = _opik._base_metric # type: ignore[attr-defined]
sys.modules["opik.evaluation.metrics"].score_result = _opik._score_result # type: ignore[attr-defined]
sys.modules["opik.evaluation.metrics"].BaseMetric = _opik._base_metric.BaseMetric # type: ignore[attr-defined]
sys.modules["opik.evaluation.metrics"].ScoreResult = _opik._score_result.ScoreResult # type: ignore[attr-defined]
# Now these resolve to the lightweight versions
from opik.evaluation.metrics import BaseMetric
from opik.evaluation.metrics.score_result import ScoreResult
# Constants
TRACE_THREAD_METRIC_TYPE = "trace_thread" # Referenced in the payload_types.py as it's not available in the scoring_commands.py process
def get_metric_class(module: types.ModuleType) -> Type[BaseMetric]:
for _, cls in inspect.getmembers(module, inspect.isclass):
if issubclass(cls, BaseMetric) and cls != BaseMetric:
return cls
return None
def to_scores(score_result: Union[ScoreResult, List[ScoreResult]]) -> List[ScoreResult]:
scores = []
if score_result is None:
return scores
if isinstance(score_result, ScoreResult):
scores = [score_result]
elif isinstance(score_result, list):
for item in score_result:
if isinstance(item, ScoreResult):
scores.append(item)
return scores
code = argv[1]
data = json.loads(argv[2])
payload_type = argv[3] if len(argv) > 3 else None
module = types.ModuleType(str(uuid.uuid4()))
try:
exec(code, module.__dict__)
except Exception:
stacktrace = "\\n".join(traceback.format_exc().splitlines()[3:])
print(json.dumps({"error": f"Field 'code' contains invalid Python code: {stacktrace}"}))
exit(1)
metric_class = get_metric_class(module)
if metric_class is None:
print(json.dumps({"error": "Field 'code' in the request doesn't contain a subclass implementation of 'opik.evaluation.metrics.BaseMetric'"}))
exit(1)
score_result : Union[ScoreResult, List[ScoreResult]] = []
try:
metric = metric_class()
# Handle trace_thread type differently - pass data as first positional argument
if payload_type == TRACE_THREAD_METRIC_TYPE:
score_result = metric.score(data)
else:
# Regular scoring - unpack data as keyword arguments
score_result = metric.score(**data)
except Exception:
stacktrace = "\\n".join(traceback.format_exc().splitlines()[3:])
print(json.dumps({"error": f"The provided 'code' and 'data' fields can't be evaluated: {stacktrace}"}))
exit(1)
scores = to_scores(score_result)
response = json.dumps({"scores": [score.__dict__ for score in scores]})
print(response)