Files
ttulttul-ComfyUI-Modal/modal_sdk.py
T
Ken SimpsonandClaude Opus 5.5 218adb848d Default COMFY_MODAL_EXECUTION_MODE to remote
Local mode runs rewritten components inside the local ComfyUI process and
exists only for developing the extension, yet it was the default, so users
who did not set the variable silently ran in it. settings now owns the
default (remote) through configured_execution_mode(), and every host-side
reader uses it. The Modal image environment pins local explicitly, as SSH
and Vast workers already do, so container code keeps its in-process
behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 11:20:40 -07:00

142 lines
4.8 KiB
Python

"""Startup bootstrap for the optional Modal Python SDK."""
from __future__ import annotations
import importlib
import importlib.util
import logging
import shlex
import shutil
import subprocess
import sys
try: # Package import inside ComfyUI; flat import inside workers and tests.
from .settings import configured_execution_mode
except ImportError: # pragma: no cover - exercised by flat imports.
from settings import configured_execution_mode
logger = logging.getLogger(__name__)
MODAL_PACKAGE_SPEC = "modal==1.4.2"
_INSTALL_TIMEOUT_SECONDS = 300
def _remote_execution_requested(execution_mode: str | None = None) -> bool:
"""Return whether startup configuration requests Modal-backed execution."""
if execution_mode is None:
return configured_execution_mode() == "remote"
return execution_mode.strip().lower() == "remote"
def _build_install_command() -> list[str] | None:
"""Build an installer command targeting the current Python interpreter."""
uv_executable = shutil.which("uv")
if uv_executable is not None:
return [
uv_executable,
"pip",
"install",
"--python",
sys.executable,
MODAL_PACKAGE_SPEC,
]
if importlib.util.find_spec("pip") is not None:
return [sys.executable, "-m", "pip", "install", MODAL_PACKAGE_SPEC]
return None
def _log_installer_output(completed_process: subprocess.CompletedProcess[str]) -> None:
"""Log captured installer output at debug level for troubleshooting."""
if completed_process.stdout.strip():
logger.debug("Modal SDK installer stdout:\n%s", completed_process.stdout.strip())
if completed_process.stderr.strip():
logger.debug("Modal SDK installer stderr:\n%s", completed_process.stderr.strip())
def _install_modal_sdk() -> bool:
"""Install the pinned Modal SDK into the interpreter running ComfyUI."""
command = _build_install_command()
if command is None:
logger.error(
"Cannot install required Modal SDK %s automatically because neither uv nor pip "
"is available for Python interpreter %s.",
MODAL_PACKAGE_SPEC,
sys.executable,
)
return False
command_text = shlex.join(command)
logger.info("Running automatic Modal SDK installation: %s", command_text)
try:
completed_process = subprocess.run(
command,
capture_output=True,
check=False,
text=True,
timeout=_INSTALL_TIMEOUT_SECONDS,
)
except subprocess.TimeoutExpired:
logger.error(
"Automatic Modal SDK installation timed out after %d seconds: %s",
_INSTALL_TIMEOUT_SECONDS,
command_text,
)
return False
except OSError as exc:
logger.error("Unable to start automatic Modal SDK installation %s: %s", command_text, exc)
return False
_log_installer_output(completed_process)
if completed_process.returncode != 0:
logger.error(
"Automatic Modal SDK installation failed with exit status %d. Retry manually: %s",
completed_process.returncode,
command_text,
)
return False
logger.info("Automatic Modal SDK installation completed successfully for %s.", MODAL_PACKAGE_SPEC)
return True
def _modal_sdk_is_importable() -> bool:
"""Return whether the Modal SDK imports without a missing-module error."""
try:
importlib.import_module("modal")
except ModuleNotFoundError as exc:
if exc.name != "modal":
logger.error(
"The Modal SDK is installed but cannot import because module %s is missing.",
exc.name,
)
return False
return True
def ensure_modal_sdk_available(execution_mode: str | None = None) -> bool:
"""Install and import the pinned Modal SDK when remote execution needs it."""
if _modal_sdk_is_importable():
logger.debug("Modal SDK is already available to Python interpreter %s.", sys.executable)
return True
if not _remote_execution_requested(execution_mode):
logger.debug("Modal SDK is unavailable, but local execution mode does not require it.")
return False
logger.warning(
"Modal SDK is missing from Python interpreter %s; installing %s automatically.",
sys.executable,
MODAL_PACKAGE_SPEC,
)
if not _install_modal_sdk():
return False
importlib.invalidate_caches()
if not _modal_sdk_is_importable():
logger.error(
"Modal SDK %s was installed but is still not importable in Python interpreter %s.",
MODAL_PACKAGE_SPEC,
sys.executable,
)
return False
logger.info("Modal SDK %s is ready for remote execution.", MODAL_PACKAGE_SPEC)
return True