From 42025e0f9446299eb11560e91e587f613df05ddb Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 27 Sep 2025 07:55:43 +0200 Subject: [PATCH] perflint: Add ruff rules for performance --- .pre-commit-config.yaml | 6 +-- pyproject.toml | 5 ++- .../policies/smolvla/smolvlm_with_expert.py | 3 +- .../common/robot_devices/cameras/opencv.py | 45 +++++++++---------- .../common/robot_devices/robots/beavrbot.py | 4 +- .../robot_devices/robots/manipulator.py | 15 ++----- .../robots/mobile_manipulator.py | 9 ++-- src/beavr/lerobot/configs/policies.py | 6 +-- .../operator/solvers/leap_solver.py | 2 +- 9 files changed, 40 insertions(+), 55 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e35477a0..f48b95c7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,8 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.2 + rev: v0.14.10 hooks: - - id: ruff + - id: ruff-check args: [--fix, --exit-non-zero-on-fix] - id: ruff-format @@ -13,6 +13,7 @@ repos: - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files + args: [--maxkb=5000] - repo: https://github.com/codespell-project/codespell rev: v2.4.1 @@ -20,4 +21,3 @@ repos: - id: codespell # See pyproject.toml for args additional_dependencies: - tomli - args: [--maxkb=5000] diff --git a/pyproject.toml b/pyproject.toml index f978f112..11976c40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,13 +154,14 @@ exclude = ["tests/artifacts/**/*.safetensors", "*_pb2.py", "*_pb2_grpc.py"] # N: pep8-naming # TODO: Uncomment rules when ready to use select = [ - "E", "W", "F", "I", "B", "C4", "T20", "N" # "SIM", "A", "S", "D", "RUF", "UP" + "ASYNC", "B", "C4", "E", "F", "I", "N", "PERF", "T20", "W" # "A", "D", "RUF", "S", "SIM", "UP" ] ignore = [ + "B008", # Perform function call in argument defaults "E501", # Line too long + "PERF203", # try-except-in-loop "T201", # Print statement found "T203", # Pprint statement found - "B008", # Perform function call in argument defaults ] [tool.ruff.lint.per-file-ignores] diff --git a/src/beavr/lerobot/common/policies/smolvla/smolvlm_with_expert.py b/src/beavr/lerobot/common/policies/smolvla/smolvlm_with_expert.py index 727e0c17..3ba35c02 100644 --- a/src/beavr/lerobot/common/policies/smolvla/smolvlm_with_expert.py +++ b/src/beavr/lerobot/common/policies/smolvla/smolvlm_with_expert.py @@ -157,8 +157,7 @@ def set_requires_grad(self): "lm_head", "text_model.model.norm.weight", ] - for layer in last_layers: - frozen_layers.append(f"text_model.model.layers.{layer}.") + frozen_layers.extend(f"text_model.model.layers.{layer}." for layer in last_layers) for name, params in self.vlm.named_parameters(): if any(k in name for k in frozen_layers): diff --git a/src/beavr/lerobot/common/robot_devices/cameras/opencv.py b/src/beavr/lerobot/common/robot_devices/cameras/opencv.py index f0e8ed24..49322fa2 100644 --- a/src/beavr/lerobot/common/robot_devices/cameras/opencv.py +++ b/src/beavr/lerobot/common/robot_devices/cameras/opencv.py @@ -46,34 +46,31 @@ def find_cameras(raise_when_empty=False, max_index_search_range=MAX_OPENCV_INDEX, mock=False) -> list[dict]: - cameras = [] if platform.system() == "Linux": print("Linux detected. Finding available camera indices through scanning '/dev/video*' ports") possible_ports = [str(port) for port in Path("/dev").glob("video*")] ports = _find_cameras(possible_ports, mock=mock) - for port in ports: - cameras.append( - { - "port": port, - "index": int(port.removeprefix("/dev/video")), - } - ) - else: - print( - "Mac or Windows detected. Finding available camera indices through " - f"scanning all indices from 0 to {MAX_OPENCV_INDEX}" - ) - possible_indices = range(max_index_search_range) - indices = _find_cameras(possible_indices, mock=mock) - for index in indices: - cameras.append( - { - "port": None, - "index": index, - } - ) - - return cameras + return [ + { + "port": port, + "index": int(port.removeprefix("/dev/video")), + } + for port in ports + ] + + print( + "Mac or Windows detected. Finding available camera indices through " + f"scanning all indices from 0 to {MAX_OPENCV_INDEX}" + ) + possible_indices = range(max_index_search_range) + indices = _find_cameras(possible_indices, mock=mock) + return [ + { + "port": None, + "index": index, + } + for index in indices + ] def _find_cameras( diff --git a/src/beavr/lerobot/common/robot_devices/robots/beavrbot.py b/src/beavr/lerobot/common/robot_devices/robots/beavrbot.py index 1077ce23..79b86144 100644 --- a/src/beavr/lerobot/common/robot_devices/robots/beavrbot.py +++ b/src/beavr/lerobot/common/robot_devices/robots/beavrbot.py @@ -457,7 +457,7 @@ def teleop_stop(self): logging.warning("WARNING: Not all subscribers acknowledged teleop stop – proceeding anyway") # Send home signals - for _, home_info in self.home_publishers.items(): + for home_info in self.home_publishers.values(): self.pub_manager.publish( home_info["host"], home_info["port"], @@ -486,7 +486,7 @@ def teleop_resume(self): logging.warning("WARNING: Not all subscribers acknowledged teleop resume – proceeding anyway") # Send home signals - for _, home_info in self.home_publishers.items(): + for home_info in self.home_publishers.values(): self.pub_manager.publish( home_info["host"], home_info["port"], diff --git a/src/beavr/lerobot/common/robot_devices/robots/manipulator.py b/src/beavr/lerobot/common/robot_devices/robots/manipulator.py index bb2a16c9..c986e290 100644 --- a/src/beavr/lerobot/common/robot_devices/robots/manipulator.py +++ b/src/beavr/lerobot/common/robot_devices/robots/manipulator.py @@ -502,17 +502,11 @@ def teleop_step( self.logs[f"read_follower_{name}_pos_dt_s"] = time.perf_counter() - before_fread_t # Create state by concatenating follower current position - state = [] - for name in self.follower_arms: - if name in follower_pos: - state.append(follower_pos[name]) + state = [follower_pos[name] for name in self.follower_arms if name in follower_pos] state = torch.cat(state) # Create action by concatenating follower goal position - action = [] - for name in self.follower_arms: - if name in follower_goal_pos: - action.append(follower_goal_pos[name]) + action = [follower_goal_pos[name] for name in self.follower_arms if name in follower_goal_pos] action = torch.cat(action) # Capture images from cameras @@ -549,10 +543,7 @@ def capture_observation(self): self.logs[f"read_follower_{name}_pos_dt_s"] = time.perf_counter() - before_fread_t # Create state by concatenating follower current position - state = [] - for name in self.follower_arms: - if name in follower_pos: - state.append(follower_pos[name]) + state = [follower_pos[name] for name in self.follower_arms if name in follower_pos] state = torch.cat(state) # Capture images from cameras diff --git a/src/beavr/lerobot/common/robot_devices/robots/mobile_manipulator.py b/src/beavr/lerobot/common/robot_devices/robots/mobile_manipulator.py index 7e6e7d34..42078917 100644 --- a/src/beavr/lerobot/common/robot_devices/robots/mobile_manipulator.py +++ b/src/beavr/lerobot/common/robot_devices/robots/mobile_manipulator.py @@ -180,12 +180,9 @@ def num_cameras(self): @property def available_arms(self): - available = [] - for name in self.leader_arms: - available.append(get_arm_id(name, "leader")) - for name in self.follower_arms: - available.append(get_arm_id(name, "follower")) - return available + return [get_arm_id(name, "leader") for name in self.leader_arms] + [ + get_arm_id(name, "follower") for name in self.follower_arms + ] def on_press(self, key): try: diff --git a/src/beavr/lerobot/configs/policies.py b/src/beavr/lerobot/configs/policies.py index 6c41ac29..0babe56e 100644 --- a/src/beavr/lerobot/configs/policies.py +++ b/src/beavr/lerobot/configs/policies.py @@ -117,14 +117,14 @@ def validate_features(self) -> None: @property def robot_state_feature(self) -> PolicyFeature | None: - for _, ft in self.input_features.items(): + for ft in self.input_features.values(): if ft.type is FeatureType.STATE: return ft return None @property def env_state_feature(self) -> PolicyFeature | None: - for _, ft in self.input_features.items(): + for ft in self.input_features.values(): if ft.type is FeatureType.ENV: return ft return None @@ -135,7 +135,7 @@ def image_features(self) -> dict[str, PolicyFeature]: @property def action_feature(self) -> PolicyFeature | None: - for _, ft in self.output_features.items(): + for ft in self.output_features.values(): if ft.type is FeatureType.ACTION: return ft return None diff --git a/src/beavr/teleop/components/operator/solvers/leap_solver.py b/src/beavr/teleop/components/operator/solvers/leap_solver.py index 128f3634..c7983794 100644 --- a/src/beavr/teleop/components/operator/solvers/leap_solver.py +++ b/src/beavr/teleop/components/operator/solvers/leap_solver.py @@ -221,7 +221,7 @@ def solve_ik(self, finger_positions, current_positions=None): # Update with the provided finger positions for finger, positions in finger_positions.items(): - full_finger_positions[finger] = positions + full_finger_positions[finger] = positions # noqa: PERF403 # Check which fingers are active (have positions) active_fingers = {