diff --git a/examples/camera_viz/pipeline/runner.py b/examples/camera_viz/pipeline/runner.py index 59273e31c..1ce37fda1 100644 --- a/examples/camera_viz/pipeline/runner.py +++ b/examples/camera_viz/pipeline/runner.py @@ -200,7 +200,7 @@ def _record_error(self, exc: BaseException, where: str) -> None: with self._error_lock: if self._error is None: self._error = exc - logger.error("VizRunner %s thread failed: %s", where, exc, exc_info=True) + logger.error("VizRunner %s thread failed: %s", where, exc, exc_info=exc) self._stop.set() with self._data_cond: self._data_cond.notify_all() diff --git a/examples/camera_viz/sources/oakd.py b/examples/camera_viz/sources/oakd.py index 6d732f7d1..a6217913f 100644 --- a/examples/camera_viz/sources/oakd.py +++ b/examples/camera_viz/sources/oakd.py @@ -30,7 +30,7 @@ import threading import time from dataclasses import dataclass, field -from typing import List, Optional +from typing import ClassVar, List, Optional import numpy as np @@ -120,7 +120,7 @@ class _OakdDevice: closes it. """ - _SOCKET_MAP = { + _SOCKET_MAP: ClassVar[dict[str, str]] = { "RGB": "CAM_A", "CAM_A": "CAM_A", "LEFT": "CAM_B", diff --git a/examples/camera_viz/sources/synthetic.py b/examples/camera_viz/sources/synthetic.py index 25c5ed414..e0c30fd03 100644 --- a/examples/camera_viz/sources/synthetic.py +++ b/examples/camera_viz/sources/synthetic.py @@ -234,27 +234,29 @@ def _produce_loop(self) -> None: diag_l = (x_grid_l + y_grid) / float(w + h) diag_r = (x_grid_r + y_grid) / float(w + h) + # Defined once, above the loop: taking phase as a parameter avoids + # rebuilding a closure over it on every generated frame. + def fill(buf, diag, phase): + r = (cp.sin((diag + phase) * 6.2831853) * 127.0 + 128.0).astype( + cp.uint8 + ) + g = ( + cp.sin((diag + phase + 0.3333) * 6.2831853) * 127.0 + 128.0 + ).astype(cp.uint8) + b = ( + cp.sin((diag + phase + 0.6667) * 6.2831853) * 127.0 + 128.0 + ).astype(cp.uint8) + buf[..., 0] = r + buf[..., 1] = g + buf[..., 2] = b + buf[..., 3] = 255 + while not self._stop.is_set(): t = (time.monotonic_ns() - self._t0_ns) * 1e-9 phase = (t * self._hue_speed_hz) % 1.0 - def fill(buf, diag): - r = (cp.sin((diag + phase) * 6.2831853) * 127.0 + 128.0).astype( - cp.uint8 - ) - g = ( - cp.sin((diag + phase + 0.3333) * 6.2831853) * 127.0 + 128.0 - ).astype(cp.uint8) - b = ( - cp.sin((diag + phase + 0.6667) * 6.2831853) * 127.0 + 128.0 - ).astype(cp.uint8) - buf[..., 0] = r - buf[..., 1] = g - buf[..., 2] = b - buf[..., 3] = 255 - - fill(self._left[self._write_idx], diag_l) - fill(self._right[self._write_idx], diag_r) + fill(self._left[self._write_idx], diag_l, phase) + fill(self._right[self._write_idx], diag_r, phase) cp.cuda.Stream.null.synchronize() with self._lock: diff --git a/examples/camera_viz/sources/zed.py b/examples/camera_viz/sources/zed.py index f49679bb2..33514640f 100644 --- a/examples/camera_viz/sources/zed.py +++ b/examples/camera_viz/sources/zed.py @@ -310,7 +310,7 @@ def _hint(): # Pyzed Mats are pitched GPU buffers — one per eye, reused every # grab() / retrieve_image() pair. - for eye, slot in self._slots.items(): + for slot in self._slots.values(): slot.zed_mat = sl.Mat() self._camera = camera diff --git a/examples/camera_viz/transports/rtp_h264_sender.py b/examples/camera_viz/transports/rtp_h264_sender.py index c4a906233..538a5f3d3 100644 --- a/examples/camera_viz/transports/rtp_h264_sender.py +++ b/examples/camera_viz/transports/rtp_h264_sender.py @@ -252,7 +252,7 @@ def _send_loop(self) -> None: raise RuntimeError( f"RtpH264Sender: encode failed {consecutive_encode_failures} " f"times in a row; surfacing to supervisor for full restart" - ) + ) from e continue for pkt in packets: diff --git a/examples/noitom/noitom_retargeting.py b/examples/noitom/noitom_retargeting.py index 2264f46ab..32193a173 100644 --- a/examples/noitom/noitom_retargeting.py +++ b/examples/noitom/noitom_retargeting.py @@ -1264,7 +1264,7 @@ def compute_robot_reference_positions( parsed = _parse_upper_body(frame) if parsed is None: return {} - torso, left, right, _pelvis_world = parsed + _torso, left, right, _pelvis_world = parsed yaw_delta = _resolve_yaw_delta(current_yaw - calib.body_yaw_isaac, settings) anchor = settings.robot_pelvis_world.astype(np.float64) positions: dict[int, np.ndarray] = {int(BodyJoint.PELVIS): anchor.copy()} @@ -1754,7 +1754,7 @@ def _solve_wrist_target( yaw_delta = _resolve_yaw_delta(_compute_torso_yaw(torso) - calib_yaw, settings) if settings.use_posture_based_arms: - shoulder_robot, elbow_robot, wrist_robot = _arm_fk_robot_blended( + _shoulder_robot, elbow_robot, wrist_robot = _arm_fk_robot_blended( arm, neutral, settings, yaw_delta, is_left ) forearm = wrist_robot - elbow_robot diff --git a/examples/retargeting/python/wuji_hand_retargeter_demo.py b/examples/retargeting/python/wuji_hand_retargeter_demo.py index 4996981d2..2b7d5ad12 100755 --- a/examples/retargeting/python/wuji_hand_retargeter_demo.py +++ b/examples/retargeting/python/wuji_hand_retargeter_demo.py @@ -54,6 +54,7 @@ import signal import sys import time +from typing import ClassVar import numpy as np @@ -147,7 +148,7 @@ class _ReplayUnpickler(pickle.Unpickler): recording may have been produced elsewhere or shared. """ - _ALLOWED = { + _ALLOWED: ClassVar[set[tuple[str, str]]] = { ("numpy", "ndarray"), ("numpy", "dtype"), ("numpy.core.multiarray", "_reconstruct"), # numpy < 2 diff --git a/examples/teleop_session_manager/python/message_channel_example.py b/examples/teleop_session_manager/python/message_channel_example.py index e5c607089..d2faf4b66 100755 --- a/examples/teleop_session_manager/python/message_channel_example.py +++ b/examples/teleop_session_manager/python/message_channel_example.py @@ -30,7 +30,9 @@ def _positive_int(value: str) -> int: try: n = int(value) except ValueError: - raise argparse.ArgumentTypeError(f"expected a positive integer, got {value!r}") + raise argparse.ArgumentTypeError( + f"expected a positive integer, got {value!r}" + ) from None if n <= 0: raise argparse.ArgumentTypeError(f"must be a positive integer, got {n}") return n @@ -44,7 +46,7 @@ def _parse_uuid_bytes(uuid_text: str) -> bytes: raise argparse.ArgumentTypeError( f"--channel-uuid: invalid UUID {uuid_text!r} (expected canonical form, " "e.g. 550e8400-e29b-41d4-a716-446655440000)" - ) + ) from None def _enqueue_outbound_message(sink, payload: bytes) -> None: diff --git a/pyproject.toml b/pyproject.toml index 5d93e2ab7..384664ef3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -132,3 +132,72 @@ packages = { isaacteleop = "src/python/isaacteleop" } [tool.scikit-build.editable] mode = "redirect" rebuild = false + +# ============================================================================== +# Ruff +# ============================================================================== +# The ruff + ruff-format pre-commit hooks previously ran with no configuration at +# all, i.e. only ruff's built-in default rules (E4/E7/E9 + F). The `select` below +# widens that to the correctness-oriented rule groups; formatting stays on +# ruff-format's defaults (88 cols), which is what the tree is already formatted to. +# +# Everything in `select` is currently clean, so the hook is enforceable as-is. +# Each `ignore` is a deliberate call, not a backlog marker -- see its comment. +[tool.ruff] +target-version = "py311" + +[tool.ruff.lint] +select = [ + "E4", "E7", "E9", # pycodestyle errors (ruff's default subset) + "F", # pyflakes + "B", # flake8-bugbear -- real bug shapes + "C4", # flake8-comprehensions + "PIE", # flake8-pie + "PERF", # perflint + "PLE", "PLW", # pylint errors + warnings + "LOG", "G", # logging correctness + "ASYNC", # async pitfalls + "RUF", # ruff-specific +] + +ignore = [ + # Adding strict= to a zip() converts a silent truncation into a runtime + # exception, so it is a behaviour change per call site, not a mechanical fix. + # Worth adopting deliberately (15 sites) rather than in a lint sweep. + "B905", + # Style-only rewrites of code that is already correct and readable: + # RUF005 turns `a + [b]` into `[*a, b]`, C408 turns dict(a=1) into {"a": 1}, + # and RUF007 turns zip(x[:-1], x[1:]) into itertools.pairwise(x). Enforcing + # any of them means churning working call sites for no behaviour change, so + # they are left to author preference. + "RUF005", "C408", "RUF007", + # Sorting __all__ alphabetically destroys the semantic grouping comments the + # package __init__ files use ("# Hand types.", "# Controller types.", ...). + "RUF022", + # RUF100 is evaluated against `select` above, so it flags every noqa written + # for a rule this config does not (yet) enable -- BLE001, PLC0415, N803 and + # friends. Re-enable once those groups are adopted. + "RUF100", + # The tree deliberately uses en/em dashes and arrows in prose and comments. + "RUF001", "RUF002", "RUF003", + # Module-level singletons (EnvConfig, the CloudXR runtime handles) are an + # intentional design choice here. + "PLW0603", + # Rebinding a loop variable to its normalized form, and small wrapper lambdas, + # both read better than the suggested rewrites in the places they occur. + "PLW2901", "PLW0108", + # The suggested comprehensions inline filtering logic that is clearer as an + # explicit loop (see EnvConfig._merge_env). + "PERF401", "PERF403", + # Targets trio/anyio. The one flagged call is a sub-millisecond os.path.isfile + # in an asyncio poll loop that already sleeps between iterations; routing it + # through an executor would cost more than the stat it replaces. + "ASYNC240", + # Flags any async def taking a `timeout` parameter; that is the established + # signature for the adb/runtime helpers and their callers. + "ASYNC109", +] + +[tool.ruff.lint.per-file-ignores] +# Tests legitimately assert on private state and re-import inside test bodies. +"**/tests/**" = ["SLF001"] diff --git a/scripts/check_copyright_year.py b/scripts/check_copyright_year.py index fe8c6b8c9..361f081d9 100644 --- a/scripts/check_copyright_year.py +++ b/scripts/check_copyright_year.py @@ -30,6 +30,7 @@ def git_last_modified_year(path: Path) -> int | None: text=True, cwd=path.parent, timeout=5, + check=False, ) if result.returncode != 0: return None @@ -41,6 +42,7 @@ def git_last_modified_year(path: Path) -> int | None: text=True, cwd=root, timeout=5, + check=False, ) if result.returncode != 0 or not result.stdout.strip(): return None diff --git a/scripts/check_lfs_pointers.py b/scripts/check_lfs_pointers.py index 3bcd3775e..7f8f04896 100755 --- a/scripts/check_lfs_pointers.py +++ b/scripts/check_lfs_pointers.py @@ -37,6 +37,7 @@ def _staged_content(path: str) -> bytes | None: proc = subprocess.run( ["git", "show", f":{path}"], capture_output=True, + check=False, ) if proc.returncode != 0: return None diff --git a/src/core/cloudxr_tests/python/test_runtime.py b/src/core/cloudxr_tests/python/test_runtime.py index 42dbfd39e..e58a3f03e 100644 --- a/src/core/cloudxr_tests/python/test_runtime.py +++ b/src/core/cloudxr_tests/python/test_runtime.py @@ -166,7 +166,7 @@ def test_explicit_exp_missing_raises(self, monkeypatch): "isaacteleop.cloudxr.runtime._is_exp_available", lambda: False ) with pytest.raises( - RuntimeError, match="cloudxr_exp|ENABLE_CLOUDXR_EXP" + RuntimeError, match=r"cloudxr_exp|ENABLE_CLOUDXR_EXP" ) as excinfo: resolve_cloudxr_runtime_module() # The message must blame the missing *artifact*: cloudxr_exp is authored @@ -240,7 +240,7 @@ def test_auto_t234_missing_raises(self, monkeypatch): monkeypatch.setattr( "isaacteleop.cloudxr.runtime._is_exp_available", lambda: False ) - with pytest.raises(RuntimeError, match="cloudxr_exp|ENABLE_CLOUDXR_EXP"): + with pytest.raises(RuntimeError, match=r"cloudxr_exp|ENABLE_CLOUDXR_EXP"): resolve_cloudxr_runtime_module() @@ -270,7 +270,7 @@ def test_missing_raises(self, tmp_path, monkeypatch): self._select(monkeypatch, "isaacteleop.cloudxr") _patch_find_spec(monkeypatch, {"isaacteleop.cloudxr": roots}) - with pytest.raises(RuntimeError, match="libcloudxr.so") as excinfo: + with pytest.raises(RuntimeError, match=r"libcloudxr\.so") as excinfo: get_sdk_path() for root in roots: assert root in str(excinfo.value) diff --git a/src/core/retargeting_engine_tests/python/test_base_retargeter.py b/src/core/retargeting_engine_tests/python/test_base_retargeter.py index 1788413f5..0abba9964 100644 --- a/src/core/retargeting_engine_tests/python/test_base_retargeter.py +++ b/src/core/retargeting_engine_tests/python/test_base_retargeter.py @@ -508,7 +508,7 @@ def test_output_selector_repr(self): class ParametricScaleRetargeter(BaseRetargeter): """Retargeter with a tunable scale parameter.""" - def __init__(self, name: str, config_file: str = None) -> None: + def __init__(self, name: str, config_file: str | None = None) -> None: # Create parameter with sync function parameters = [ FloatParameter( diff --git a/src/core/retargeting_engine_tests/python/test_haptic_sink.py b/src/core/retargeting_engine_tests/python/test_haptic_sink.py index 762b1ab68..21ae6801a 100644 --- a/src/core/retargeting_engine_tests/python/test_haptic_sink.py +++ b/src/core/retargeting_engine_tests/python/test_haptic_sink.py @@ -122,9 +122,10 @@ def test_connect_rejects_mismatched_upstream_type(self) -> None: sink = HapticSink("sink", device) leaf = ValueInput("upstream", TactileVector(5)) - with pytest.raises(Exception): - # Compatibility check raises a TypeError or AssertionError depending - # on which TensorType detects the mismatch first; either is fine. + # Which exception surfaces depends on which TensorType detects the mismatch + # first; NDArrayType currently raises ValueError. Naming the accepted set + # beats a bare Exception, which would also swallow an unrelated failure. + with pytest.raises((TypeError, AssertionError, ValueError)): sink.connect({"left": leaf.output("value")}) diff --git a/src/core/retargeting_engine_tests/python/test_parameter_state.py b/src/core/retargeting_engine_tests/python/test_parameter_state.py index 566c8d6da..9965fc747 100644 --- a/src/core/retargeting_engine_tests/python/test_parameter_state.py +++ b/src/core/retargeting_engine_tests/python/test_parameter_state.py @@ -158,13 +158,12 @@ def test_save_and_load_to_file(self): def test_load_nonexistent_file_doesnt_error(self): """Test loading from nonexistent file doesn't error.""" param = FloatParameter(name="value", description="Value", default_value=1.0) - try: - ParameterState( - name="test", parameters=[param], config_file="/nonexistent/path.json" - ) - except Exception as e: - # Should not raise error during construction - assert False, f"Unexpected exception raised: {e}" + # Must not raise during construction; letting any exception propagate + # fails the test with the original traceback (and unlike `assert False`, + # this still holds under `python -O`). + ParameterState( + name="test", parameters=[param], config_file="/nonexistent/path.json" + ) def test_load_from_file_after_save(self): """Test loading from saved file.""" diff --git a/src/core/teleop_session_manager_tests/python/test_teleop_session.py b/src/core/teleop_session_manager_tests/python/test_teleop_session.py index 586b58033..ed7d24939 100644 --- a/src/core/teleop_session_manager_tests/python/test_teleop_session.py +++ b/src/core/teleop_session_manager_tests/python/test_teleop_session.py @@ -603,8 +603,6 @@ def poll_tracker(self, deviceio_session): class MockOpenXRHandles: """Mock OpenXR session handles.""" - pass - class MockOpenXRSession: """Mock OpenXR session that supports context manager protocol.""" @@ -985,7 +983,7 @@ def test_external_leaves_missing_all_inputs(self): config = make_config(pipeline) session = TeleopSession(config) - with pytest.raises(ValueError, match="external.*non-DeviceIO"): + with pytest.raises(ValueError, match=r"external.*non-DeviceIO"): session._validate_external_inputs(None) def test_external_leaves_missing_some_inputs(self): @@ -1573,7 +1571,7 @@ def test_step_raises_on_missing_external_inputs(self): with mock_session_dependencies(): session = TeleopSession(config) with session: - with pytest.raises(ValueError, match="external.*non-DeviceIO"): + with pytest.raises(ValueError, match=r"external.*non-DeviceIO"): session.step() def test_step_checks_plugin_health_every_60_frames(self): diff --git a/src/postprocessing/egocentric_hand_reconstruction/quality_control/detect_jumpy_hand_from_world_results.py b/src/postprocessing/egocentric_hand_reconstruction/quality_control/detect_jumpy_hand_from_world_results.py index 8a23cf745..83b4b51f2 100755 --- a/src/postprocessing/egocentric_hand_reconstruction/quality_control/detect_jumpy_hand_from_world_results.py +++ b/src/postprocessing/egocentric_hand_reconstruction/quality_control/detect_jumpy_hand_from_world_results.py @@ -379,7 +379,7 @@ def _load_track_info_detection_lost( for b, s in enumerate(stats): # Find vis_mask for this track: track_info has track_id -> {index, vis_mask}; index matches our b vis_mask = None - for tid, info in tracks.items(): + for info in tracks.values(): if info.get("index") == b: vis_mask = info.get("vis_mask") break diff --git a/src/python/isaacteleop/cloudxr/env_config.py b/src/python/isaacteleop/cloudxr/env_config.py index 4408f6809..227b7cc4f 100644 --- a/src/python/isaacteleop/cloudxr/env_config.py +++ b/src/python/isaacteleop/cloudxr/env_config.py @@ -13,6 +13,7 @@ import shlex import warnings from pathlib import Path +from typing import ClassVar class EnvConfig: @@ -43,7 +44,7 @@ class EnvConfig: ) # Default env var name -> default value. Empty string or None means "resolve later" - _DEFAULT_ENV: dict[str, str | None] = { + _DEFAULT_ENV: ClassVar[dict[str, str | None]] = { "XR_RUNTIME_JSON": None, # resolved from openxr_run_dir() "NV_CXR_RUNTIME_DIR": None, # resolved from openxr_run_dir() "NV_CXR_OUTPUT_DIR": None, # resolved from ensure_logs_dir() diff --git a/src/python/isaacteleop/cloudxr/launcher.py b/src/python/isaacteleop/cloudxr/launcher.py index 0236b8e15..33b0f65ba 100644 --- a/src/python/isaacteleop/cloudxr/launcher.py +++ b/src/python/isaacteleop/cloudxr/launcher.py @@ -589,6 +589,7 @@ def _cleanup_stale_runtime(env_cfg: EnvConfig) -> None: ["fuser", "-k", "-TERM", ipc_socket], capture_output=True, timeout=5, + check=False, ) if result.returncode == 0: time.sleep(1) diff --git a/src/python/isaacteleop/cloudxr/oob_teleop_adb.py b/src/python/isaacteleop/cloudxr/oob_teleop_adb.py index 4405b56cd..727155dd0 100644 --- a/src/python/isaacteleop/cloudxr/oob_teleop_adb.py +++ b/src/python/isaacteleop/cloudxr/oob_teleop_adb.py @@ -637,7 +637,9 @@ def open_url_on_headset(url: str) -> tuple[int, str]: redact_control_token(" ".join(shlex.quote(c) for c in full)), ) try: - proc = subprocess.run(full, capture_output=True, text=True, timeout=30) + proc = subprocess.run( + full, capture_output=True, text=True, timeout=30, check=False + ) except subprocess.TimeoutExpired as e: partial = ( (e.stderr or e.stdout or b"") diff --git a/src/python/isaacteleop/haptic_devices/controller.py b/src/python/isaacteleop/haptic_devices/controller.py index d78355c9a..91cc9ed82 100644 --- a/src/python/isaacteleop/haptic_devices/controller.py +++ b/src/python/isaacteleop/haptic_devices/controller.py @@ -79,9 +79,7 @@ def __init__( ) # Latest-wins per endpoint within a frame; emitted and cleared by flush. self._pending: dict[Endpoint, _Pulse] = {} - self._error_logged: dict[Endpoint, bool] = { - endpoint: False for endpoint in self._endpoints - } + self._error_logged: dict[Endpoint, bool] = dict.fromkeys(self._endpoints, False) def accepted_type(self) -> TensorGroupType: return ControllerHapticPulse() diff --git a/src/python/isaacteleop/haptic_devices/push_tensor.py b/src/python/isaacteleop/haptic_devices/push_tensor.py index 73f262d5e..fd988dcf2 100644 --- a/src/python/isaacteleop/haptic_devices/push_tensor.py +++ b/src/python/isaacteleop/haptic_devices/push_tensor.py @@ -86,9 +86,7 @@ def __init__( ) # Latest-wins per endpoint within a frame; emitted and cleared by flush. self._pending: dict[Endpoint, list[float]] = {} - self._error_logged: dict[Endpoint, bool] = { - endpoint: False for endpoint in self._endpoints - } + self._error_logged: dict[Endpoint, bool] = dict.fromkeys(self._endpoints, False) def accepted_type(self) -> TensorGroupType: return self._accepted_type diff --git a/src/python/isaacteleop/retargeters/dex_hand_retargeter.py b/src/python/isaacteleop/retargeters/dex_hand_retargeter.py index b056de146..e0555398c 100644 --- a/src/python/isaacteleop/retargeters/dex_hand_retargeter.py +++ b/src/python/isaacteleop/retargeters/dex_hand_retargeter.py @@ -323,7 +323,7 @@ def _update_yaml(self, yaml_path: str, urdf_path: str) -> Optional[str]: return None except Exception as e: - logger.error(f"Error updating YAML {yaml_path}: {e}") + logger.error("Error updating YAML %s: %s", yaml_path, e) return None def _compute_hand(self, poses: Dict[str, np.ndarray]) -> np.ndarray: @@ -418,7 +418,7 @@ def _compute_hand(self, poses: Dict[str, np.ndarray]) -> np.ndarray: with torch.enable_grad(), torch.inference_mode(False): return self._dex_hand.retarget(ref_value) # type: ignore except Exception as e: - logger.error(f"Error in retargeting: {e}") + logger.error("Error in retargeting: %s", e) return np.zeros(len(self._dex_hand.optimizer.robot.dof_joint_names)) diff --git a/src/python/isaacteleop/retargeting_engine/deviceio_source_nodes/interface.py b/src/python/isaacteleop/retargeting_engine/deviceio_source_nodes/interface.py index 35849b147..c8e5e32e0 100644 --- a/src/python/isaacteleop/retargeting_engine/deviceio_source_nodes/interface.py +++ b/src/python/isaacteleop/retargeting_engine/deviceio_source_nodes/interface.py @@ -71,7 +71,6 @@ def get_tracker(self) -> "ITracker": Returns: The ITracker instance (e.g., HeadTracker, HandTracker, ControllerTracker) """ - pass @abstractmethod def poll_tracker(self, deviceio_session: Any) -> RetargeterIO: @@ -87,4 +86,3 @@ def poll_tracker(self, deviceio_session: Any) -> RetargeterIO: Dict mapping input names to TensorGroups containing raw tracker data, matching this source's input_spec(). """ - pass diff --git a/src/python/isaacteleop/retargeting_engine/interface/base_retargeter.py b/src/python/isaacteleop/retargeting_engine/interface/base_retargeter.py index 9e7bce35a..e1d033d60 100644 --- a/src/python/isaacteleop/retargeting_engine/interface/base_retargeter.py +++ b/src/python/isaacteleop/retargeting_engine/interface/base_retargeter.py @@ -111,7 +111,6 @@ def input_spec(self) -> RetargeterIOType: Returns: Dict[str, TensorGroupType] - Input specification """ - pass @abstractmethod def output_spec(self) -> RetargeterIOType: @@ -121,7 +120,6 @@ def output_spec(self) -> RetargeterIOType: Returns: Dict[str, TensorGroupType] - Output specification """ - pass @abstractmethod def _compute_fn( @@ -153,7 +151,6 @@ def _compute_fn( outputs: Output tensor groups to populate (Dict[str, TensorGroup]) context: Compute context containing graph time and future metadata """ - pass # ======================================================================== # Public convenience API — not part of any abstract contract diff --git a/src/python/isaacteleop/retargeting_engine/interface/tensor_type.py b/src/python/isaacteleop/retargeting_engine/interface/tensor_type.py index e2c7b75e0..8315645b1 100644 --- a/src/python/isaacteleop/retargeting_engine/interface/tensor_type.py +++ b/src/python/isaacteleop/retargeting_engine/interface/tensor_type.py @@ -66,7 +66,6 @@ def _check_instance_compatibility(self, other: "TensorType") -> bool: Returns: True if the instances are compatible, False otherwise """ - pass @abstractmethod def validate_value(self, value: Any) -> None: @@ -83,7 +82,6 @@ def validate_value(self, value: Any) -> None: Raises: TypeError: If the value does not conform to this tensor type """ - pass def __repr__(self) -> str: return f"{self.__class__.__name__}(name='{self._name}')" diff --git a/src/python/isaacteleop/retargeting_engine/interface/tunable_parameter.py b/src/python/isaacteleop/retargeting_engine/interface/tunable_parameter.py index c2dbecfd8..236554170 100644 --- a/src/python/isaacteleop/retargeting_engine/interface/tunable_parameter.py +++ b/src/python/isaacteleop/retargeting_engine/interface/tunable_parameter.py @@ -27,22 +27,18 @@ class ParameterSpec(ABC): @abstractmethod def validate(self, value: Any) -> bool: """Check if a value is valid for this parameter.""" - pass @abstractmethod def get_default_value(self) -> Any: """Get the default value for this parameter.""" - pass @abstractmethod def serialize(self, value: Any) -> Any: """Serialize a value to a JSON-compatible format.""" - pass @abstractmethod def deserialize(self, value: Any) -> Any: """Deserialize a value from a JSON-compatible format.""" - pass @dataclass diff --git a/src/python/isaacteleop/retargeting_engine_ui/multi_retargeter_tuning_ui.py b/src/python/isaacteleop/retargeting_engine_ui/multi_retargeter_tuning_ui.py index 661babfb0..523dadd29 100644 --- a/src/python/isaacteleop/retargeting_engine_ui/multi_retargeter_tuning_ui.py +++ b/src/python/isaacteleop/retargeting_engine_ui/multi_retargeter_tuning_ui.py @@ -368,7 +368,7 @@ def _render_floating_layout(self) -> None: imgui.set_next_window_size(400, 500, imgui.FIRST_USE_EVER) # Create independent floating window - expanded, opened = imgui.begin(f"{name}##floating", closable=False) + expanded, _opened = imgui.begin(f"{name}##floating", closable=False) if expanded: self._render_retargeter_params(name, param_state) imgui.end() diff --git a/src/python/isaacteleop/rig/launcher.py b/src/python/isaacteleop/rig/launcher.py index 0881f84f2..4c643fe58 100644 --- a/src/python/isaacteleop/rig/launcher.py +++ b/src/python/isaacteleop/rig/launcher.py @@ -111,6 +111,7 @@ def _check_python_can_import_cloudxr(env: Mapping[str, str]) -> None: [sys.executable, "-c", "import isaacteleop.cloudxr"], env=dict(env), capture_output=True, + check=False, ) if probe.returncode != 0: raise PreflightError(