From 20c22a27996576b7471fa1721933a3146af39849 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Dec 2025 02:03:12 +0100 Subject: [PATCH 1/3] chore(ci): make keyword matching more conservative (#2711) --- .github/workflows/issue_labeler.yml | 44 +++++++++++------------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/.github/workflows/issue_labeler.yml b/.github/workflows/issue_labeler.yml index 27ca2b5f9..438184e3f 100644 --- a/.github/workflows/issue_labeler.yml +++ b/.github/workflows/issue_labeler.yml @@ -42,38 +42,26 @@ jobs: // Keyword Heuristics - // Domain Specific - if (matches(/\b(bug|error|issue|fault|crash|exception)\b/i)) labelsToAdd.add('bug'); - if (matches(/\b(feature|enhancement|improvement|support|implement|proposal)\b/i)) labelsToAdd.add('enhancement'); - if (matches(/\b(question|help|how to||clarify|explain|unclear)\b/i)) labelsToAdd.add('question'); - if (matches(/\b(maintenance|documentation|docs|readme|tutorial|guide|wiki)\b/i)) labelsToAdd.add('documentation'); - if (matches(/\b(example|script|sample|demo|notebook)s?\b/i)) labelsToAdd.add('examples'); + if (matches(/\b(bug|error|crash|exception)\b/i)) labelsToAdd.add('bug'); + if (matches(/\b(new feature|enhancement|improvement|proposal|feature request)\b/i)) labelsToAdd.add('enhancement'); + if (matches(/\b(question|how to|clarify|explain|how do i|help me|question about)\b/i)) labelsToAdd.add('question'); + if (matches(/\b(documentation|docs?|readme|tutorial|wiki|typo|docstring)\b/i)) labelsToAdd.add('documentation'); + if (matches(/\b(example|sample|demo|notebook)s?\b/i)) labelsToAdd.add('examples'); if (matches(/\b(datasets?|data loader|data augmentation|data preprocessing)\b/i)) labelsToAdd.add('dataset'); if (matches(/\b(mujoco|isaac|simulation|sim)\b/i)) labelsToAdd.add('simulation'); - if (matches(/\b(train|training|loss|optimizer|backward|gradient|wandb|sac)\b/i)) labelsToAdd.add('training'); - if (matches(/\b(rerun|plot|video|render|visualiz|gif)/i)) labelsToAdd.add('visualization'); - if (matches(/\b(camera|realsense|lidar|depth|sensor|imu|microphone|rgbd)\b/i)) labelsToAdd.add('sensors'); - if (matches(/\b(aloha|koch|so-100|so100|mobile|teleop|manipulator|robots?)\b/i)) labelsToAdd.add('robots'); + if (matches(/\b(train|training|optimizer|gradient|wandb|sac)\b/i)) labelsToAdd.add('training'); + if (matches(/\b(rerun|plot|render|rendering|visualizer)/i)) labelsToAdd.add('visualization'); + if (matches(/\b(cameras?|opencv|realsense|lidars?|sensors?|imus?|microphones?|rgbd|encoders?)\b/i)) labelsToAdd.add('sensors'); + if (matches(/\b(urdf|actuators?|calibration|end-effector|kinematics)\b/i)) labelsToAdd.add('robots'); if (matches(/\b(teleop|teleoperator|controller|leader|follower|joystick|gamepad)\b/i)) labelsToAdd.add('teleoperators'); - if (matches(/\b(policy|policies|p0licy)\b/i)) labelsToAdd.add('policies'); - if (matches(/\b(processors?|pipeline)\b/i)) labelsToAdd.add('processor'); - if (matches(/\b(eval|evaluate|evaluation|metrics?|score|benchmark)\b/i)) labelsToAdd.add('evaluation'); - - // Infrastructure & Code Quality + if (matches(/\b(policy|policies|model?)\b/i)) labelsToAdd.add('policies'); + if (matches(/\b(processor|pipeline|preprocessor|postprocessor)s?\b/i)) labelsToAdd.add('processor'); + if (matches(/\b(eval|evaluate|evaluation|metrics?|score|benchmarks?)\b/i)) labelsToAdd.add('evaluation'); if (matches(/\b(tests?|pytest|unittest|failing test)\b/i)) labelsToAdd.add('tests'); - if (matches(/\b(ci|github actions|workflow|gha|actions?|pipeline)\b/i)) { - labelsToAdd.add('CI'); - labelsToAdd.add('github_actions'); - } - if (matches(/\b(perf|latency|throughput|fps|speed|performance)\b/i)) labelsToAdd.add('performance'); - if (matches(/\b(dependency|requirements|pip|conda|install error|importerror|package not found)\b/i)) labelsToAdd.add('dependencies'); - if (matches(/\b(python|pyproject|requirements(\.txt)?|pip install|typing error)\b/i)) labelsToAdd.add('python'); - - // Documentation & Meta - if (matches(/\b(doc|documentation|docs|readme|typo|how to)\b/i)) labelsToAdd.add('documentation'); - if (matches(/\b(refactor|cleanup|restructure|rename|modernize code)\b/i)) labelsToAdd.add('refactor'); - if (matches(/\b(release|changelog|version bump|cut a release|tag v)\b/i)) labelsToAdd.add('release'); - if (matches(/\b(breaking change|major change)\b/i)) labelsToAdd.add('breaking change'); + if (matches(/\b(ci|github actions?|github workflows?|gha|docker|pypi)\b/i)) labelsToAdd.add('CI'); + if (matches(/\b(perf|latency|throughput|fps|speed|performance|slow|fast|slower|faster|memory usage)\b/i)) labelsToAdd.add('performance'); + if (matches(/\b(dependency|dependencies|pip|install error|importerror|package not found|pyproject)\b/i)) labelsToAdd.add('dependencies'); + if (matches(/\b(configuration|config|arguments?|input feature|dracuss)\b/i)) labelsToAdd.add('configuration'); // Apply Labels const labels = Array.from(labelsToAdd).filter(Boolean); From a06f4b914045453b243a5d0049bbcc5f15d4dc86 Mon Sep 17 00:00:00 2001 From: Salman Chishti Date: Wed, 24 Dec 2025 09:42:29 +0000 Subject: [PATCH 2/3] Upgrade GitHub Actions for Node 24 compatibility (#2691) --- .github/workflows/fast_tests.yml | 2 +- .github/workflows/full_tests.yml | 4 ++-- .github/workflows/nightly.yml | 4 ++-- .github/workflows/quality.yml | 4 ++-- .github/workflows/release.yml | 6 +++--- .github/workflows/security.yml | 2 +- .github/workflows/unbound_deps_tests.yml | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/fast_tests.yml b/.github/workflows/fast_tests.yml index ffd3195c2..10ec91199 100644 --- a/.github/workflows/fast_tests.yml +++ b/.github/workflows/fast_tests.yml @@ -62,7 +62,7 @@ jobs: HF_HOME: /mnt/cache/.cache/huggingface HF_LEROBOT_HOME: /mnt/cache/.cache/huggingface/lerobot steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false lfs: true diff --git a/.github/workflows/full_tests.yml b/.github/workflows/full_tests.yml index 7962d4a3a..7bf2cb78c 100644 --- a/.github/workflows/full_tests.yml +++ b/.github/workflows/full_tests.yml @@ -61,7 +61,7 @@ jobs: HF_HOME: /mnt/cache/.cache/huggingface HF_LEROBOT_HOME: /mnt/cache/.cache/huggingface/lerobot steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false @@ -127,7 +127,7 @@ jobs: sudo apt-get update sudo apt-get install git-lfs git lfs install - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 94d5cc9f2..45bfb9bd5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -52,7 +52,7 @@ jobs: sudo apt-get update sudo apt-get install git-lfs git lfs install - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false @@ -87,7 +87,7 @@ jobs: sudo apt-get update sudo apt-get install git-lfs git lfs install - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index e9f73ed23..0dc94cdd4 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -43,12 +43,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.10' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c61307d6c..bcab4c262 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,12 +38,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.10' @@ -135,7 +135,7 @@ jobs: env: MUJOCO_GL: egl steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 04497307b..50c0c1fc3 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 # zizmor: ignore[unpinned-uses] + uses: actions/checkout@v6 # zizmor: ignore[unpinned-uses] with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/unbound_deps_tests.yml b/.github/workflows/unbound_deps_tests.yml index bf93dcda6..3908bdc3d 100644 --- a/.github/workflows/unbound_deps_tests.yml +++ b/.github/workflows/unbound_deps_tests.yml @@ -49,7 +49,7 @@ jobs: HF_HOME: /mnt/cache/.cache/huggingface HF_LEROBOT_HOME: /mnt/cache/.cache/huggingface/lerobot steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false @@ -101,7 +101,7 @@ jobs: sudo apt-get update sudo apt-get install git-lfs git lfs install - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: lfs: true persist-credentials: false From 12043b3b5cfd104c7d6201992d761fa39576fb5c Mon Sep 17 00:00:00 2001 From: Alexis Alva Date: Wed, 24 Dec 2025 11:45:14 -0300 Subject: [PATCH 3/3] fix: use importlib.metadata for plugin discovery to support PEP 660 (#2687) --- src/lerobot/utils/import_utils.py | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/lerobot/utils/import_utils.py b/src/lerobot/utils/import_utils.py index 0dd9db516..3a01aee88 100644 --- a/src/lerobot/utils/import_utils.py +++ b/src/lerobot/utils/import_utils.py @@ -14,8 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. import importlib +import importlib.metadata import logging -import pkgutil from typing import Any from draccus.choice_types import ChoiceRegistry @@ -132,24 +132,30 @@ def make_device_from_device_class(config: ChoiceRegistry) -> Any: def register_third_party_plugins() -> None: """ - Discover and import third-party lerobot_* plugins so they can register themselves. + Discover and import third-party LeRobot plugins so they can register themselves. - Scans top-level modules on sys.path for packages starting with - 'lerobot_robot_', 'lerobot_camera_', 'lerobot_teleoperator_' or 'lerobot_policy_' and imports them. + This function uses `importlib.metadata` to find packages installed in the environment + (including editable installs) starting with 'lerobot_robot_', 'lerobot_camera_', + 'lerobot_teleoperator_', or 'lerobot_policy_' and imports them. """ prefixes = ("lerobot_robot_", "lerobot_camera_", "lerobot_teleoperator_", "lerobot_policy_") imported: list[str] = [] failed: list[str] = [] - for module_info in pkgutil.iter_modules(): - name = module_info.name - if name.startswith(prefixes): - try: - importlib.import_module(name) - imported.append(name) - logging.info("Imported third-party plugin: %s", name) - except Exception: - logging.exception("Could not import third-party plugin: %s", name) - failed.append(name) + def attempt_import(module_name: str): + try: + importlib.import_module(module_name) + imported.append(module_name) + logging.info("Imported third-party plugin: %s", module_name) + except Exception: + logging.exception("Could not import third-party plugin: %s", module_name) + failed.append(module_name) + + for dist in importlib.metadata.distributions(): + dist_name = dist.metadata.get("Name") + if not dist_name: + continue + if dist_name.startswith(prefixes): + attempt_import(dist_name) logging.debug("Third-party plugin import summary: imported=%s failed=%s", imported, failed)