发布

  • [OPIK-6091] [BE] fix: resolve opik.* submodule imports in Python sandbox (#6396)

    frostbyte_neo 发布于 2026-04-21 13:42:33 +00:00

    • [OPIK-6091] fix: resolve opik.* submodule imports in sandbox

    The lightweight import patching in #6319 registers stub modules with
    __path__ = [] and a _FallbackModule.__getattr__ that loads the real
    opik on attribute access. That fallback fires for from opik import X
    but not for from opik.evaluation.metrics.conversation import X
    submodule resolution goes through the import machinery (parent
    __path__ + finders), which never consults __getattr__. Any user
    metric importing from opik.evaluation.metrics.{conversation,heuristics,llm_judges,aggregated_metric} (or other non-stubbed paths) fails with ModuleNotFoundError.

    Adds an _OpikFallbackFinder on sys.meta_path that intercepts
    unresolved opik.* submodule imports, triggers the same
    _load_real_opik() used by the attribute fallback, and defers to the
    standard PathFinder with the now-real __path__. Lightweight path
    (BaseMetric / ScoreResult only) stays unchanged.

    • refactor: unify opik import fallback into a single stub class

    Address review feedback: the separate _OpikFallbackFinder was tacked
    on alongside _FallbackModule instead of being part of it. Merge them
    into _LazyOpikStub so one class owns both protocols:

    • __getattr__ for attribute access (from opik import Client)
    • find_spec for submodule resolution (from opik.x.y import z)

    The same instance is registered in both sys.modules (as the parent
    module stub) and sys.meta_path (as the finder). All cleanup — stub
    eviction from sys.modules and sys.meta_path — lives inside
    _load_real_opik, which is now idempotent via an early exit on empty
    _stubs.

    • Keep _FallbackModule name

    • test: cover the sys.meta_path submodule fallback

    Adds two unit tests to TestLightweightOpikPackage that pin down the new
    find_spec behavior:

    • test_submodule_import_of_non_stubbed_opik_child_triggers_real_load:
      sets up stubs + finder, imports from
      opik.evaluation.metrics.conversation, asserts the stubs get evicted and
      the real submodule resolves to the installed opik package.

    • test_lightweight_path_stays_lightweight_with_finder_installed: same
      setup, then a BaseMetric/ScoreResult-only flow, asserts no heavy opik
      modules get loaded and the stubs remain in place.

    Mirrors the subprocess pattern used by the existing tests in the class
    so state stays isolated across test runs.

    下载附件