From 1624fc1797beb243674c907ffce86d8a79d8cc20 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Sun, 12 Apr 2026 09:56:03 +0200 Subject: [PATCH] is_available checks centralized --- src/lerobot/motors/dynamixel/dynamixel.py | 4 +--- src/lerobot/motors/feetech/feetech.py | 4 +--- .../groot/action_head/cross_attention_dit.py | 4 +--- src/lerobot/policies/wall_x/modeling_wall_x.py | 5 ++--- .../teleoperators/keyboard/teleop_keyboard.py | 4 ++-- src/lerobot/utils/import_utils.py | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/lerobot/motors/dynamixel/dynamixel.py b/src/lerobot/motors/dynamixel/dynamixel.py index b5aa3ee11..3e5a08135 100644 --- a/src/lerobot/motors/dynamixel/dynamixel.py +++ b/src/lerobot/motors/dynamixel/dynamixel.py @@ -23,7 +23,7 @@ from copy import deepcopy from enum import Enum from typing import TYPE_CHECKING -from lerobot.utils.import_utils import is_package_available, require_package +from lerobot.utils.import_utils import _dynamixel_sdk_available, require_package from ..encoding_utils import decode_twos_complement, encode_twos_complement from ..motors_bus import Motor, MotorCalibration, NameOrID, SerialMotorsBus, Value, get_address @@ -36,8 +36,6 @@ from .tables import ( MODEL_RESOLUTION, ) -_dynamixel_sdk_available = is_package_available("dynamixel-sdk", import_name="dynamixel_sdk") - if TYPE_CHECKING or _dynamixel_sdk_available: import dynamixel_sdk as dxl else: diff --git a/src/lerobot/motors/feetech/feetech.py b/src/lerobot/motors/feetech/feetech.py index 629c0877e..837505830 100644 --- a/src/lerobot/motors/feetech/feetech.py +++ b/src/lerobot/motors/feetech/feetech.py @@ -18,7 +18,7 @@ from enum import Enum from pprint import pformat from typing import TYPE_CHECKING -from lerobot.utils.import_utils import is_package_available, require_package +from lerobot.utils.import_utils import _feetech_sdk_available, require_package from ..encoding_utils import decode_sign_magnitude, encode_sign_magnitude from ..motors_bus import Motor, MotorCalibration, NameOrID, SerialMotorsBus, Value, get_address @@ -35,8 +35,6 @@ from .tables import ( SCAN_BAUDRATES, ) -_feetech_sdk_available = is_package_available("feetech-servo-sdk", import_name="scservo_sdk") - if TYPE_CHECKING or _feetech_sdk_available: import scservo_sdk as scs else: diff --git a/src/lerobot/policies/groot/action_head/cross_attention_dit.py b/src/lerobot/policies/groot/action_head/cross_attention_dit.py index 32e9f64fe..a4cd1a0b7 100755 --- a/src/lerobot/policies/groot/action_head/cross_attention_dit.py +++ b/src/lerobot/policies/groot/action_head/cross_attention_dit.py @@ -20,9 +20,7 @@ import torch import torch.nn.functional as F # noqa: N812 from torch import nn -from lerobot.utils.import_utils import is_package_available, require_package - -_diffusers_available = is_package_available("diffusers") +from lerobot.utils.import_utils import _diffusers_available, require_package if TYPE_CHECKING or _diffusers_available: from diffusers import ConfigMixin, ModelMixin diff --git a/src/lerobot/policies/wall_x/modeling_wall_x.py b/src/lerobot/policies/wall_x/modeling_wall_x.py index b90b7e564..968d94129 100644 --- a/src/lerobot/policies/wall_x/modeling_wall_x.py +++ b/src/lerobot/policies/wall_x/modeling_wall_x.py @@ -52,8 +52,9 @@ from torch.nn import CrossEntropyLoss from lerobot.utils.constants import ACTION, OBS_STATE from lerobot.utils.import_utils import ( _peft_available, + _qwen_vl_utils_available, + _torchdiffeq_available, _transformers_available, - is_package_available, require_package, ) @@ -71,8 +72,6 @@ from .constant import ( TOKENIZER_MAX_LENGTH, ) -_torchdiffeq_available = is_package_available("torchdiffeq") -_qwen_vl_utils_available = is_package_available("qwen-vl-utils", import_name="qwen_vl_utils") _wallx_deps_available = ( _transformers_available and _peft_available and _torchdiffeq_available and _qwen_vl_utils_available ) diff --git a/src/lerobot/teleoperators/keyboard/teleop_keyboard.py b/src/lerobot/teleoperators/keyboard/teleop_keyboard.py index b62b17f8f..0f1c7d7f1 100644 --- a/src/lerobot/teleoperators/keyboard/teleop_keyboard.py +++ b/src/lerobot/teleoperators/keyboard/teleop_keyboard.py @@ -23,7 +23,7 @@ from typing import Any from lerobot.types import RobotAction from lerobot.utils.decorators import check_if_already_connected, check_if_not_connected -from lerobot.utils.import_utils import is_package_available +from lerobot.utils.import_utils import _pynput_available from ..teleoperator import Teleoperator from ..utils import TeleopEvents @@ -33,7 +33,7 @@ from .configuration_keyboard import ( KeyboardTeleopConfig, ) -PYNPUT_AVAILABLE = is_package_available("pynput") +PYNPUT_AVAILABLE = _pynput_available keyboard = None if PYNPUT_AVAILABLE: try: diff --git a/src/lerobot/utils/import_utils.py b/src/lerobot/utils/import_utils.py index 0fefbd973..425bf44eb 100644 --- a/src/lerobot/utils/import_utils.py +++ b/src/lerobot/utils/import_utils.py @@ -95,13 +95,29 @@ def require_package(pkg_name: str, extra: str, import_name: str | None = None) - ) +# ── Centralised availability flags ──────────────────────────────────────── +# Every optional-dependency check lives here so that the rest of the codebase +# can simply ``from lerobot.utils.import_utils import _foo_available``. +# Do NOT define ad-hoc ``is_package_available(...)`` calls in other modules. + +# ML / training _transformers_available = is_package_available("transformers") _peft_available = is_package_available("peft") _scipy_available = is_package_available("scipy") +_diffusers_available = is_package_available("diffusers") +_torchdiffeq_available = is_package_available("torchdiffeq") + +# Hardware SDKs +_dynamixel_sdk_available = is_package_available("dynamixel-sdk", import_name="dynamixel_sdk") +_feetech_sdk_available = is_package_available("feetech-servo-sdk", import_name="scservo_sdk") _reachy2_sdk_available = is_package_available("reachy2_sdk") _can_available = is_package_available("python-can", "can") _unitree_sdk_available = is_package_available("unitree-sdk2py", "unitree_sdk2py") + +# Misc +_pynput_available = is_package_available("pynput") _pygame_available = is_package_available("pygame") +_qwen_vl_utils_available = is_package_available("qwen-vl-utils", import_name="qwen_vl_utils") def make_device_from_device_class(config: ChoiceRegistry) -> Any: