Skip to content

fix: ensure motors module passes MyPy type checks#2732

Closed
yurekami wants to merge 4 commits intohuggingface:mainfrom
yurekami:fix/motors-mypy-type-checks
Closed

fix: ensure motors module passes MyPy type checks#2732
yurekami wants to merge 4 commits intohuggingface:mainfrom
yurekami:fix/motors-mypy-type-checks

Conversation

@yurekami
Copy link
Contributor

Summary

  • Fixes 62 mypy type errors in the lerobot.motors module
  • Enables strict mypy type checking for the motors module by uncommenting the configuration in pyproject.toml

Changes Made

Protocol Classes (motors_bus.py)

  • Updated PortHandler, PacketHandler, GroupSyncRead, and GroupSyncWrite Protocol classes to use class-level attribute declarations instead of __init__ body declarations
  • Added missing broadcastPing method to PacketHandler Protocol

Type Annotations

  • Fixed return type of _get_motor_model (returns str, not int)
  • Fixed return type of _get_ids_values_dict (returns dict[int, Value], not list[str])
  • Fixed _read return type to tuple[int, int, int] (was tuple[int, int])
  • Changed _normalize to accept Mapping[int, Value] for covariance
  • Used Sequence[NameOrID] instead of list[NameOrID] for covariant list parameters in public APIs

Method Signatures

  • Updated enable_torque in base class to accept int | str | list[str] | None to match disable_torque
  • Updated _get_half_turn_homings signature to use dict[str, Value] consistently
  • Fixed subclass method signatures to match parent class signatures (LSP compliance)

Other Fixes

  • Added explicit return None for functions returning Optional types
  • Added type annotation for data_list: dict[int, int] in _broadcast_ping
  • Added int() casts for MotorCalibration arguments
  • Used # type: ignore[method-assign] for intentional monkeypatch in feetech.py
  • Fixed variable references in RangeFinderGUI.__init__ (using self.groups instead of groups after initialization)

Test Plan

  • mypy src/lerobot/motors --show-error-codes passes with no errors
  • Existing motor tests pass (requires hardware dependencies)

Fixes #1723

🤖 Generated with Claude Code

This commit fixes 62 mypy type errors in the motors module by:

- Updating Protocol classes (PortHandler, PacketHandler, GroupSyncRead,
  GroupSyncWrite) to use class-level attribute declarations instead of
  __init__ body declarations
- Adding missing `broadcastPing` method to PacketHandler Protocol
- Fixing return type annotations (e.g., `_get_motor_model` returns str, not int)
- Fixing parameter types to use `Sequence` for covariant list parameters
- Fixing `Mapping` for covariant dict value types in `_normalize`
- Updating method signatures to be consistent across parent and child classes
  (disable_torque, enable_torque, _get_half_turn_homings)
- Adding explicit `int()` casts for MotorCalibration arguments
- Adding explicit `return None` for functions returning Optional types
- Adding type annotations for variables like `data_list: dict[int, int]`
- Using `# type: ignore[method-assign]` for intentional monkeypatch
- Fixing variable references (using `self.groups` instead of `groups`)

Fixes huggingface#1723

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions github-actions bot added the robots Issues concerning robots HW interfaces label Dec 29, 2025
@imstevenpmwork imstevenpmwork self-assigned this Dec 30, 2025
@imstevenpmwork imstevenpmwork self-requested a review December 30, 2025 13:57
Copy link
Collaborator

@imstevenpmwork imstevenpmwork left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, thanks for contributing! Good job with this PR 😄
I left some minor comments, but they are mostly questions for my understanding.
Also, the linter CI is failing, could you please run pre-commit run -a?
Thanks again!

return ids_values

def _get_half_turn_homings(self, positions: dict[NameOrID, Value]) -> dict[NameOrID, Value]:
def _get_half_turn_homings(self, positions: dict[str, Value]) -> dict[str, Value]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the change for _get_half_turn_homings motivated from the fact that the function is only ever called with a dict[str,Value] as an input?

return mins, maxes

def _normalize(self, ids_values: dict[int, int]) -> dict[int, float]:
def _normalize(self, ids_values: Mapping[int, Value]) -> dict[int, float]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation behind this change?

model = self.motors[motor].model
addr, length = get_address(self.model_ctrl_table, model, data_name)

int_value: int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do int_value = int(value) right away and delete the else down below ?

model = next(iter(models))
addr, length = get_address(self.model_ctrl_table, model, data_name)

int_ids_values: dict[int, int]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in here too? int_ids_values = {id_: int(val) for id_, val in raw_ids_values.items()} and remove the else block below

@imstevenpmwork
Copy link
Collaborator

Hello @yurekami , have you had any time to check on this ?

@imstevenpmwork
Copy link
Collaborator

Superseded by: #2939

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

robots Issues concerning robots HW interfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ensure the motors module passes MyPy type checks

2 participants