SuperAPI AI Directory

lazy-import-refactor

Coding & development

View repository

Updated 10-15 21:33

About this skill

Lazy Import Refactor

Module-level import torch / import tensorflow Steps for migrating heavy native dependencies to function-internal lazy imports + test side-effect prediction + CI-equivalent verification requirements.

When to Use

  • import <library> standalone SIGSEGV (CUDA driver absent + triton C-ext segfault, etc.)
  • Want to defer heavy imports to shorten startup time
  • Want to make heavy native deps unnecessary for WebAPI-only users
  • Design study for requesting lazy import conversion of upstream libs from a downstream project

Relevant real example: on Linux + triton + CUDA driver absent, import <ML ライブラリ> caused SIGSEGV → there is a case permanently resolved by eliminating module-level imports of torch / transformers

Step 1: Pre-flight grep — exhaustive identification of impact scope

All module-level imports (col 0 only):

find src -name "*.py" | while read f; do
  awk -v fn="$f" '/^(import torch|from torch|import torchvision|from torchvision|import tensorflow|from tensorflow)/{print fn":"NR":"$0}' "$f"
done

All module attribute patches on the test side:

find tests -name "*.py" | while read f; do
  awk -v fn="$f" '/@patch.*\.(torch|tensorflow|jax)|patch\.object.*\.(torch|tensorflow|jax)/{print fn":"NR":"$0}' "$f"
done

Moving a module-level import into a function makes that module's module.torch attribute disappear.On the test side, @patch("path.to.module.torch") all locations using it will break with AttributeError , so a pre-flight grep is mandatory.

Step 2: Refactor Pattern

# Before (module-level)
import torch

class Foo:
    def bar(self, x: torch.Tensor) -> torch.Tensor:
        with torch.no_grad():
            ...

# After (TYPE_CHECKING + function-internal)
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    import torch


class Foo:
    def bar(self, x: torch.Tensor) -> torch.Tensor:
        import torch  # lazy load
        with torch.no_grad():
            ...

Required items:

  • from __future__ import annotations add at the top (stringify type hints, avoid runtime evaluation)
  • At the top of functions used at runtime, import torch redeclare
  • module-level の bare import torch delete

Step 3: Test side-effect handling

# Before
@patch("your_package.core.heavy_deps.torch")
def test_foo(mock_torch):
    ...

# After
def test_foo(monkeypatch):
    import sys
    from unittest.mock import MagicMock
    mock_torch = MagicMock()
    monkeypatch.setitem(sys.modules, "torch", mock_torch)
    ...

For detailed patterns (context manager mock, cuda.is_available, getattr-based access, etc.), see test-side-effects.md .

Step 4: Verification — always verify with a CI-equivalent filter

Refer to the project's testing rules (e.g., the "verify locally with a CI-equivalent filter" section of rules/testing.md ).

-m unit Shortened filters such as these are insufficient for verification (the reason this SKILL exists — there is a real example where marker differences on the submodule side could not be reproduced with a shortened filter and were first detected in downstream CI). Run the CI workflow's filter locally with an exact match.

For independent packages within a monorepo (submodules, etc.):

cd <package-path>
uv run pytest -m "not downloads_and_runs_model and not calls_real_webapi"

Step 5: Cross-repo PR order

For a lib used as a submodule:

  1. Confirm fix + CI-equivalent test pass on the lib side
  2. Open PR on the lib side → wait for merge
  3. After merge, open a PR in the downstream project to update the submodule pin

If the order is reversed, it will be first detected in downstream CI, requiring a chain of hot-fix PRs.

gh pr create When running, if the kit's submodule pre-PR check hook (hook_pre_pr_submodule_check.py) is installed, it requires confirmation of CI-equivalent test execution for PRs containing submodule changes (bypass is CI-EQUIV-TESTED marker comment)。

Anti-patterns

  • module-level upper lib import: from transformers.models.clip import CLIPProcessor requires lazy conversion because transformers eagerly loads torch. Even if not directly import torch , all imports that drag in heavy native deps are targets
  • Handled only within TYPE_CHECKING: cast(<heavy_lib>.Type, ...) や isinstance(x, <heavy_lib>.Type) cannot be completely escaped in locations requiring runtime evaluation such as this → from __future__ import annotations both stringifying type hints and in-function import are mandatory
  • Missing subprocess regression testAdd a test in the same PR to verify whether lazy importification is working. In a fresh interpreter, import <lib>; assert 'torch' not in sys.modules pattern is recommended (avoid session pollution via subprocess)
  • -m unit local verification with: If CI uses an independent marker (standard etc.), always verify with the filter in the CI configuration