From 4fbae17e77847b652fed0c9b299c46271d8787de Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Sun, 4 Jan 2026 18:49:42 +0100 Subject: [PATCH 01/32] adds ruff --- .flake8 | 23 --------- .pre-commit-config.yaml | 37 +++++--------- pyproject.toml | 104 ++++++++++++++++++++++++++-------------- 3 files changed, 79 insertions(+), 85 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 9b4a023d685..00000000000 --- a/.flake8 +++ /dev/null @@ -1,23 +0,0 @@ -[flake8] -show-source=True -statistics=True -per-file-ignores=*/__init__.py:F401 -# E402: Module level import not at top of file -# E501: Line too long -# W503: Line break before binary operator -# E203: Whitespace before ':' -> conflicts with black -# D401: First line should be in imperative mood -# R504: Unnecessary variable assignment before return statement. -# R505: Unnecessary elif after return statement -# SIM102: Use a single if-statement instead of nested if-statements -# SIM117: Merge with statements for context managers that have same scope. -# SIM118: Checks for key-existence checks against dict.keys() calls. -ignore=E402,E501,W503,E203,D401,R504,R505,SIM102,SIM117,SIM118 -max-line-length = 120 -max-complexity = 30 -exclude=_*,.vscode,.git,docs/** -# docstrings -docstring-convention=google -# annotations -suppress-none-returning=True -allow-star-arg-any=True diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60a76b06d70..426a84b59b7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,18 +4,16 @@ # SPDX-License-Identifier: BSD-3-Clause repos: - - repo: https://github.com/python/black - rev: 24.3.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.10 hooks: - - id: black - args: ["--line-length", "120", "--unstable"] - - repo: https://github.com/pycqa/flake8 - rev: 7.0.0 - hooks: - - id: flake8 - additional_dependencies: [flake8-simplify, flake8-return] + # Run the linter + - id: ruff + args: ["--fix"] + # Run the formatter + - id: ruff-format - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: check-symlinks @@ -31,21 +29,8 @@ repos: - id: check-shebang-scripts-are-executable - id: detect-private-key - id: debug-statements - - repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - name: isort (python) - args: ["--profile", "black", "--filter-files"] - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 - hooks: - - id: pyupgrade - args: ["--py310-plus"] - # FIXME: This is a hack because Pytorch does not like: torch.Tensor | dict aliasing - exclude: "source/isaaclab/isaaclab/envs/common.py|source/isaaclab/isaaclab/ui/widgets/image_plot.py|source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py" - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + rev: v2.4.1 hooks: - id: codespell additional_dependencies: @@ -57,7 +42,7 @@ repos: # hooks: # - id: pyright - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.1 + rev: v1.5.5 hooks: - id: insert-license files: \.(py|ya?ml)$ @@ -69,7 +54,7 @@ repos: exclude: "source/isaaclab_mimic/|scripts/imitation_learning/isaaclab_mimic/" # Apache 2.0 license for mimic files - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.1 + rev: v1.5.5 hooks: - id: insert-license files: ^(source/isaaclab_mimic|scripts/imitation_learning/isaaclab_mimic)/.*\.py$ diff --git a/pyproject.toml b/pyproject.toml index 8ed72cfdeee..a0390abbe32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,26 +1,65 @@ -[tool.isort] +[tool.ruff] +line-length = 120 +target-version = "py310" -py_version = 310 -line_length = 120 -group_by_package = true +# Exclude directories +extend-exclude = [ + "docs", + "logs", + "_isaac_sim", + ".vscode", + "_*", + ".git", +] -# Files to skip -skip_glob = ["docs/*", "logs/*", "_isaac_sim/*", ".vscode/*"] +[tool.ruff.lint] +# Enable flake8 rules and other useful ones +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "UP", # pyupgrade + "C90", # mccabe complexity + "D", # pydocstyle + "SIM", # flake8-simplify + "RET", # flake8-return +] -# Order of imports -sections = [ - "FUTURE", - "STDLIB", - "THIRDPARTY", - "ASSETS_FIRSTPARTY", - "FIRSTPARTY", - "EXTRA_FIRSTPARTY", - "TASK_FIRSTPARTY", - "LOCALFOLDER", +# Ignore specific rules (matching your flake8 config) +ignore = [ + "E402", # Module level import not at top of file + "E501", # Line too long (handled by formatter) + "E203", # Whitespace before ':' (conflicts with formatter) + "D401", # First line should be in imperative mood + "RET504", # Unnecessary variable assignment before return statement + "RET505", # Unnecessary elif after return statement + "SIM102", # Use a single if-statement instead of nested if-statements + "SIM117", # Merge with statements for context managers + "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() ] -# Extra standard libraries considered as part of python (permissive licenses -extra_standard_library = [ +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] # Allow unused imports in __init__.py files + +[tool.ruff.lint.mccabe] +max-complexity = 30 + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.lint.isort] +# Import ordering configuration +known-first-party = [ + "isaaclab", + "isaaclab_assets", + "isaaclab_rl", + "isaaclab_mimic", + "isaaclab_tasks", + "config", +] +known-third-party = [ + # Extra standard libraries "numpy", "h5py", "open3d", @@ -39,30 +78,23 @@ extra_standard_library = [ "tqdm", "torchvision", "transformers", - "einops", # Needed for transformers, doesn't always auto-install + "einops", "packaging", -] -# Imports from Isaac Sim and Omniverse -known_third_party = [ - "isaacsim.core.api", - "isaacsim.replicator.common", - "omni.replicator.core", + # Isaac Sim and Omniverse + "isaacsim", + "omni", "pxr", - "omni.kit.*", "warp", "carb", "Semantics", ] -# Imports from this repository -known_first_party = "isaaclab" -known_assets_firstparty = "isaaclab_assets" -known_extra_firstparty = [ - "isaaclab_rl", - "isaaclab_mimic", -] -known_task_firstparty = "isaaclab_tasks" -# Imports from the local folder -known_local_folder = "config" + +[tool.ruff.format] +# Use Black-compatible formatting +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" [tool.pyright] From 3aeea1d72c9bcdf83bbb8cbcf717fc80f0fda45d Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Sun, 4 Jan 2026 19:09:09 +0100 Subject: [PATCH 02/32] fixes import ordering --- pyproject.toml | 72 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a0390abbe32..174e6d5e866 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,6 @@ target-version = "py310" # Exclude directories extend-exclude = [ - "docs", "logs", "_isaac_sim", ".vscode", @@ -49,46 +48,71 @@ max-complexity = 30 convention = "google" [tool.ruff.lint.isort] -# Import ordering configuration -known-first-party = [ - "isaaclab", - "isaaclab_assets", - "isaaclab_rl", - "isaaclab_mimic", - "isaaclab_tasks", - "config", +# Match isort behavior +combine-as-imports = true +force-sort-within-sections = true +order-by-type = false + +# Import sections order +section-order = [ + "future", + "standard-library", + "omniverse-library", + "first-party", + "isaaclab-rl-library", + "isaaclab-mimic-library", + "isaaclab-tasks-library", + "isaaclab-assets-library", + "local-folder", ] -known-third-party = [ - # Extra standard libraries + +# Treat these as stdlib (even though they aren't) +extra-standard-library = [ "numpy", - "h5py", - "open3d", "torch", + "einops", "tensordict", + "warp", + "scipy", + "open3d", + "torchvision", + "transformers", + "h5py", + "yaml", + "toml", "bpy", + "trimesh", "matplotlib", "gymnasium", "gym", - "scipy", "hid", - "yaml", "prettytable", - "toml", - "trimesh", "tqdm", - "torchvision", - "transformers", - "einops", "packaging", - # Isaac Sim and Omniverse - "isaacsim", - "omni", + "pytest", +] + +# Third-party packages +known-third-party = [ + "isaacsim*", + "omni*", "pxr", - "warp", "carb", "Semantics", ] +"known-first-party" = ["isaaclab"] +"known-local-folder" = ["config"] + +# Custom section names +[tool.ruff.lint.isort.sections] + +"isaaclab-assets-library" = ["isaaclab_assets"] +"isaaclab-rl-library" = ["isaaclab_rl"] +"isaaclab-mimic-library" = ["isaaclab_mimic"] +"isaaclab-tasks-library" = ["isaaclab_tasks"] + + [tool.ruff.format] # Use Black-compatible formatting quote-style = "double" From 42eb43b1b43607a7f34b27495efc6d7d637b8c47 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Sun, 4 Jan 2026 19:10:14 +0100 Subject: [PATCH 03/32] fixes omni import --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 174e6d5e866..ad7e0ba5991 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ order-by-type = false section-order = [ "future", "standard-library", - "omniverse-library", + "third-party", "first-party", "isaaclab-rl-library", "isaaclab-mimic-library", From 59c7162f89a10a1ad096e33416b5a2c3dab01603 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Sun, 4 Jan 2026 19:33:44 +0100 Subject: [PATCH 04/32] fixes order --- pyproject.toml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ad7e0ba5991..5fb153ce259 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ select = [ "I", # isort "UP", # pyupgrade "C90", # mccabe complexity - "D", # pydocstyle + # "D", # pydocstyle "SIM", # flake8-simplify "RET", # flake8-return ] @@ -34,6 +34,7 @@ ignore = [ "RET504", # Unnecessary variable assignment before return statement "RET505", # Unnecessary elif after return statement "SIM102", # Use a single if-statement instead of nested if-statements + "SIM108", # Use ternary operator instead of if-else statement "SIM117", # Merge with statements for context managers "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() ] @@ -50,8 +51,8 @@ convention = "google" [tool.ruff.lint.isort] # Match isort behavior combine-as-imports = true -force-sort-within-sections = true -order-by-type = false +order-by-type = true +from-first = false # Import sections order section-order = [ @@ -75,11 +76,16 @@ extra-standard-library = [ "warp", "scipy", "open3d", + "cv2", "torchvision", "transformers", "h5py", "yaml", "toml", + "wandb", + "tensorboard", + "hydra", + "omegaconf", "bpy", "trimesh", "matplotlib", From f33e04aee07a109331f2bfdb6e6c7d5ad2aadaa4 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 11:45:19 +0100 Subject: [PATCH 05/32] fixes spellchecks --- docker/docker-compose.yaml | 2 +- docs/source/deployment/docker.rst | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 1759c58ded6..09fde19be7c 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -4,7 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Here we set the parts that would -# be re-used between services to an +# be reused between services to an # extension field # https://docs.docker.com/compose/compose-file/compose-file-v3/#extension-fields x-default-isaac-lab-volumes: &default-isaac-lab-volumes diff --git a/docs/source/deployment/docker.rst b/docs/source/deployment/docker.rst index 9f214ce49d4..2c4aeb7cbea 100644 --- a/docs/source/deployment/docker.rst +++ b/docs/source/deployment/docker.rst @@ -47,7 +47,7 @@ needed to run Isaac Lab inside a Docker container. A subset of these are summari Dockerfiles which end with something else, (i.e. ``Dockerfile.ros2``) build an `image extension <#isaac-lab-image-extensions>`_. * **docker-compose.yaml**: Creates mounts to allow direct editing of Isaac Lab code from the host machine that runs the container. It also creates several named volumes such as ``isaac-cache-kit`` to - store frequently re-used resources compiled by Isaac Sim, such as shaders, and to retain logs, data, and documents. + store frequently reused resources compiled by Isaac Sim, such as shaders, and to retain logs, data, and documents. * **.env.base**: Stores environment variables required for the ``base`` build process and the container itself. ``.env`` files which end with something else (i.e. ``.env.ros2``) define these for `image extension <#isaac-lab-image-extensions>`_. * **docker-compose.cloudxr-runtime.patch.yaml**: A patch file that is applied to enable CloudXR Runtime support for diff --git a/pyproject.toml b/pyproject.toml index 150c4f2620f..020afc67778 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,4 +120,4 @@ reportPrivateUsage = "warning" skip = '*.usd,*.usda,*.usdz,*.svg,*.png,_isaac_sim*,*.bib,*.css,*/_build' quiet-level = 0 # the world list should always have words in lower case -ignore-words-list = "haa,slq,collapsable,buss,reacher" +ignore-words-list = "haa,slq,collapsable,buss,reacher,thirdparty" From 32253c0223458d85c2e08467e1448fc2f20e4680 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 11:45:44 +0100 Subject: [PATCH 06/32] section order --- pyproject.toml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 020afc67778..f056581dda6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ combine-as-imports = true order-by-type = true from-first = false -# Import sections order +# Custom import sections section-order = [ "future", "standard-library", @@ -65,22 +65,26 @@ section-order = [ "local-folder", ] -# Omniverse extensions -known-omniverse-extensions = [ - "isaacsim*", - "omni*", +[tool.ruff.lint.isort.sections] +# Define what belongs in each custom section + +"omniverse-extensions" = [ + "isaacsim", + "omni", "pxr", "carb", "usdrt", "Semantics", ] -# Isaac Lab extensions -known-isaaclab-extensions = [ - "isaaclab*", +"isaaclab-extensions" = [ + "isaaclab", + "isaaclab_assets", + "isaaclab_mimic", + "isaaclab_rl", + "isaaclab_tasks", ] - [tool.ruff.format] # Use Black-compatible formatting quote-style = "double" From a53767c7aec772cbe98ab78507cecc3ab3d3f08a Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 11:54:08 +0100 Subject: [PATCH 07/32] fixes another typo --- pyproject.toml | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f056581dda6..a9e001a87c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,13 +54,21 @@ combine-as-imports = true order-by-type = true from-first = false -# Custom import sections +# Custom import sections with separate sections for each Isaac Lab extension section-order = [ "future", "standard-library", "third-party", + # Group omniverse extensions separately since they are run-time dependencies + # which are pulled in by Isaac Lab extensions "omniverse-extensions", - "isaaclab-extensions", + # Group Isaac Lab extensions together since they are all part of the Isaac Lab project + "isaaclab", + "isaaclab-assets", + "isaaclab-rl", + "isaaclab-mimic", + "isaaclab-tasks", + # First-party is reserved for project templates "first-party", "local-folder", ] @@ -75,15 +83,14 @@ section-order = [ "carb", "usdrt", "Semantics", + "curobo", ] -"isaaclab-extensions" = [ - "isaaclab", - "isaaclab_assets", - "isaaclab_mimic", - "isaaclab_rl", - "isaaclab_tasks", -] +"isaaclab" = ["isaaclab"] +"isaaclab-assets" = ["isaaclab_assets"] +"isaaclab-rl" = ["isaaclab_rl"] +"isaaclab-mimic" = ["isaaclab_mimic"] +"isaaclab-tasks" = ["isaaclab_tasks"] [tool.ruff.format] # Use Black-compatible formatting From 2c862e420f622f3d0d97b4bff18c46298dead041 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 11:54:29 +0100 Subject: [PATCH 08/32] ff --- source/isaaclab/test/assets/test_rigid_object_collection.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/isaaclab/test/assets/test_rigid_object_collection.py b/source/isaaclab/test/assets/test_rigid_object_collection.py index 3e75bf6c14a..d59daee84a7 100644 --- a/source/isaaclab/test/assets/test_rigid_object_collection.py +++ b/source/isaaclab/test/assets/test_rigid_object_collection.py @@ -17,6 +17,7 @@ """Rest everything follows.""" import ctypes + import pytest import torch @@ -511,7 +512,7 @@ def test_object_state_properties(sim, num_envs, num_cubes, device, with_offset, torch.testing.assert_close(object_state_w[..., 3:7], object_link_state_w[..., 3:7]) # lin_vel will not match - # center of mass vel will be constant (i.e. spining around com) + # center of mass vel will be constant (i.e. spinning around com) torch.testing.assert_close( torch.zeros_like(object_com_state_w[..., 7:10]), object_com_state_w[..., 7:10], From b334faf97e89bc044d73b55317e810cc9567daa3 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 11:58:39 +0100 Subject: [PATCH 09/32] make ruff skip file --- docs/source/refs/snippets/tutorial_modify_direct_rl_env.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py index 98e1765a11d..13e150418a3 100644 --- a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py +++ b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: BSD-3-Clause -# fmt: off +# ruff: noqa # [start-init-import] from .h1_env import H1Env, H1EnvCfg @@ -25,6 +25,7 @@ # [start-h1_env-import] from isaaclab_assets import H1_CFG + # [end-h1_env-import] # [start-h1_env-spaces] From 621cb6a90da1c5d06dca4607c9a566b29a600232 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:02:39 +0100 Subject: [PATCH 10/32] fixes ruff check --- source/isaaclab/test/utils/test_configclass.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/isaaclab/test/utils/test_configclass.py b/source/isaaclab/test/utils/test_configclass.py index b37af093fa0..0c024be03f3 100644 --- a/source/isaaclab/test/utils/test_configclass.py +++ b/source/isaaclab/test/utils/test_configclass.py @@ -18,13 +18,14 @@ import copy import os -import pytest -import torch from collections.abc import Callable from dataclasses import MISSING, asdict, field from functools import wraps from typing import Any, ClassVar +import pytest +import torch + from isaaclab.utils.configclass import configclass from isaaclab.utils.dict import class_to_dict, dict_to_md5_hash, update_class_from_dict from isaaclab.utils.io import dump_yaml, load_yaml @@ -790,9 +791,9 @@ def test_functions_config(): """Tests having functions as values in the configuration instance.""" cfg = FunctionsDemoCfg() # check types - assert cfg.__annotations__["func"] == type(dummy_function1) - assert cfg.__annotations__["wrapped_func"] == type(wrapped_dummy_function3) - assert cfg.__annotations__["func_in_dict"] == dict + assert cfg.__annotations__["func"] is type(dummy_function1) + assert cfg.__annotations__["wrapped_func"] is type(wrapped_dummy_function3) + assert cfg.__annotations__["func_in_dict"] is dict # check calling assert cfg.func() == 1 assert cfg.wrapped_func() == 4 @@ -992,10 +993,10 @@ def test_config_with_class_type(): # since python 3.10, annotations are stored as strings annotations = {k: eval(v) if isinstance(v, str) else v for k, v in cfg.__annotations__.items()} # check types - assert annotations["class_name_1"] == type + assert annotations["class_name_1"] is type assert annotations["class_name_2"] == type[DummyClass] assert annotations["class_name_3"] == type[DummyClass] - assert annotations["class_name_4"] == ClassVar[type[DummyClass]] + assert annotations["class_name_4"] is ClassVar[type[DummyClass]] # check values assert cfg.class_name_1 == DummyClass assert cfg.class_name_2 == DummyClass From 1263e80d9bddaa9249b221843ece24b04f5dc366 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:03:56 +0100 Subject: [PATCH 11/32] makes code simpler --- tools/conftest.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tools/conftest.py b/tools/conftest.py index 28fd493aca0..52ae4023077 100644 --- a/tools/conftest.py +++ b/tools/conftest.py @@ -5,7 +5,6 @@ import contextlib import os -import pytest # Platform-specific imports for real-time output streaming import select @@ -13,11 +12,12 @@ import sys import time +import pytest +from junitparser import Error, JUnitXml, TestCase, TestSuite + # Third-party imports from prettytable import PrettyTable -from junitparser import Error, JUnitXml, TestCase, TestSuite - import tools.test_settings as test_settings @@ -144,11 +144,7 @@ def run_individual_tests(test_files, workspace_root, isaacsim_ci): env = os.environ.copy() # Determine timeout for this test - timeout = ( - test_settings.PER_TEST_TIMEOUTS[file_name] - if file_name in test_settings.PER_TEST_TIMEOUTS - else test_settings.DEFAULT_TIMEOUT - ) + timeout = test_settings.PER_TEST_TIMEOUTS.get(file_name, test_settings.DEFAULT_TIMEOUT) # Prepare command cmd = [ @@ -409,12 +405,14 @@ def pytest_sessionstart(session): - test_status[test_path]["errors"] - test_status[test_path]["skipped"] ) - per_test_result_table.add_row([ - test_path, - test_status[test_path]["result"], - f"{test_status[test_path]['time_elapsed']:0.2f}", - f"{num_tests_passed}/{test_status[test_path]['tests']}", - ]) + per_test_result_table.add_row( + [ + test_path, + test_status[test_path]["result"], + f"{test_status[test_path]['time_elapsed']:0.2f}", + f"{num_tests_passed}/{test_status[test_path]['tests']}", + ] + ) summary_str += per_test_result_table.get_string() From 23f58046efac4d5584faa6aaa49bc74d052d8ec3 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:38:04 +0100 Subject: [PATCH 12/32] fixes local imports --- pyproject.toml | 1 + scripts/reinforcement_learning/ray/launch.py | 19 ++++++++++--------- .../test/benchmarking/conftest.py | 4 +++- .../isaaclab_tasks/test/test_environments.py | 4 ++-- .../test_environments_with_stage_in_memory.py | 6 ++++-- .../test/test_factory_environments.py | 4 ++-- .../test/test_lift_teddy_bear.py | 4 ++-- .../test/test_multi_agent_environments.py | 5 +++-- .../isaaclab_tasks/test/test_record_video.py | 8 +++++--- 9 files changed, 32 insertions(+), 23 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a9e001a87c1..aa1cf45fb8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ ignore = [ "RET504", # Unnecessary variable assignment before return statement "RET505", # Unnecessary elif after return statement "SIM102", # Use a single if-statement instead of nested if-statements + "SIM103", # Return the negated condition directly "SIM108", # Use ternary operator instead of if-else statement "SIM117", # Merge with statements for context managers "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() diff --git a/scripts/reinforcement_learning/ray/launch.py b/scripts/reinforcement_learning/ray/launch.py index a9f621cb9b1..453a6f65de5 100644 --- a/scripts/reinforcement_learning/ray/launch.py +++ b/scripts/reinforcement_learning/ray/launch.py @@ -3,15 +3,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -import argparse -import pathlib -import subprocess -import yaml - -import util -from jinja2 import Environment, FileSystemLoader -from kubernetes import config - """This script helps create one or more KubeRay clusters. Usage: @@ -34,6 +25,16 @@ --num_workers 1 2 --num_clusters 1 \ --worker_accelerator nvidia-l4 nvidia-tesla-t4 --gpu_per_worker 1 2 4 """ + +import argparse +import pathlib +import subprocess + +import util +import yaml +from jinja2 import Environment, FileSystemLoader +from kubernetes import config + RAY_DIR = pathlib.Path(__file__).parent diff --git a/source/isaaclab_tasks/test/benchmarking/conftest.py b/source/isaaclab_tasks/test/benchmarking/conftest.py index 20ddad8b548..50927383dcb 100644 --- a/source/isaaclab_tasks/test/benchmarking/conftest.py +++ b/source/isaaclab_tasks/test/benchmarking/conftest.py @@ -4,9 +4,11 @@ # SPDX-License-Identifier: BSD-3-Clause import json + import pytest -import env_benchmark_test_utils as utils +# Local imports should be imported last +import env_benchmark_test_utils as utils # isort: skip # Global variable for storing KPI data GLOBAL_KPI_STORE = {} diff --git a/source/isaaclab_tasks/test/test_environments.py b/source/isaaclab_tasks/test/test_environments.py index 3f0b9536825..2acd2c36652 100644 --- a/source/isaaclab_tasks/test/test_environments.py +++ b/source/isaaclab_tasks/test/test_environments.py @@ -23,10 +23,10 @@ import pytest -from env_test_utils import _run_environments, setup_environment - import isaaclab_tasks # noqa: F401 +# Local imports should be imported last +from env_test_utils import _run_environments, setup_environment # isort: skip @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) @pytest.mark.parametrize("task_name", setup_environment(include_play=False, factory_envs=False, multi_agent=False)) diff --git a/source/isaaclab_tasks/test/test_environments_with_stage_in_memory.py b/source/isaaclab_tasks/test/test_environments_with_stage_in_memory.py index b10ca715ff0..8e1eadab4ec 100644 --- a/source/isaaclab_tasks/test/test_environments_with_stage_in_memory.py +++ b/source/isaaclab_tasks/test/test_environments_with_stage_in_memory.py @@ -24,10 +24,12 @@ import pytest -from env_test_utils import _run_environments, setup_environment - import isaaclab_tasks # noqa: F401 +# Local imports should be imported last +from env_test_utils import _run_environments, setup_environment # isort: skip + + # note, running an env test without stage in memory then # running an env test with stage in memory causes IsaacLab to hang. # so, here we run all envs with stage in memory separately diff --git a/source/isaaclab_tasks/test/test_factory_environments.py b/source/isaaclab_tasks/test/test_factory_environments.py index d29208b63b7..419d7774bbc 100644 --- a/source/isaaclab_tasks/test/test_factory_environments.py +++ b/source/isaaclab_tasks/test/test_factory_environments.py @@ -15,10 +15,10 @@ import pytest -from env_test_utils import _check_random_actions, setup_environment - import isaaclab_tasks # noqa: F401 +# Local imports should be imported last +from env_test_utils import _check_random_actions, setup_environment # isort: skip @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) @pytest.mark.parametrize("task_name", setup_environment(factory_envs=True, multi_agent=False)) diff --git a/source/isaaclab_tasks/test/test_lift_teddy_bear.py b/source/isaaclab_tasks/test/test_lift_teddy_bear.py index d60b16b7244..99c5fa0fda2 100644 --- a/source/isaaclab_tasks/test/test_lift_teddy_bear.py +++ b/source/isaaclab_tasks/test/test_lift_teddy_bear.py @@ -24,10 +24,10 @@ import pytest -from env_test_utils import _run_environments - import isaaclab_tasks # noqa: F401 +# Local imports should be imported last +from env_test_utils import _run_environments # isort: skip @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) def test_lift_teddy_bear_environment(num_envs, device): diff --git a/source/isaaclab_tasks/test/test_multi_agent_environments.py b/source/isaaclab_tasks/test/test_multi_agent_environments.py index 0d72c3427e6..478cb3942e1 100644 --- a/source/isaaclab_tasks/test/test_multi_agent_environments.py +++ b/source/isaaclab_tasks/test/test_multi_agent_environments.py @@ -16,10 +16,11 @@ import pytest -from env_test_utils import _check_random_actions, setup_environment - import isaaclab_tasks # noqa: F401 +# Local imports should be imported last +from env_test_utils import _check_random_actions, setup_environment # isort: skip + @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) @pytest.mark.parametrize("task_name", setup_environment(multi_agent=True)) diff --git a/source/isaaclab_tasks/test/test_record_video.py b/source/isaaclab_tasks/test/test_record_video.py index 9a6d95e303a..a84eb846e88 100644 --- a/source/isaaclab_tasks/test/test_record_video.py +++ b/source/isaaclab_tasks/test/test_record_video.py @@ -13,18 +13,20 @@ """Rest everything follows.""" -import gymnasium as gym import os + +import gymnasium as gym import pytest import torch import omni.usd -from env_test_utils import setup_environment - import isaaclab_tasks # noqa: F401 from isaaclab_tasks.utils import parse_env_cfg +# Local imports should be imported last +from env_test_utils import setup_environment # isort: skip + @pytest.fixture(scope="function") def setup_video_params(): From faecba8f83e563633670488022d5a5c2ef296446 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:38:36 +0100 Subject: [PATCH 13/32] fixes temp file --- scripts/tools/test/test_cosmos_prompt_gen.py | 7 ++++--- scripts/tools/test/test_hdf5_to_mp4.py | 9 +++++---- scripts/tools/test/test_mp4_to_hdf5.py | 11 ++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/scripts/tools/test/test_cosmos_prompt_gen.py b/scripts/tools/test/test_cosmos_prompt_gen.py index 859edece9b4..17f1764d914 100644 --- a/scripts/tools/test/test_cosmos_prompt_gen.py +++ b/scripts/tools/test/test_cosmos_prompt_gen.py @@ -7,16 +7,17 @@ import json import os -import pytest import tempfile +import pytest + from scripts.tools.cosmos.cosmos_prompt_gen import generate_prompt, main @pytest.fixture(scope="class") def temp_templates_file(): """Create temporary templates file.""" - temp_file = tempfile.NamedTemporaryFile(suffix=".json", delete=False) + temp_file = tempfile.NamedTemporaryFile(suffix=".json", delete=False) # noqa: SIM115 # Create test templates test_templates = { @@ -39,7 +40,7 @@ def temp_templates_file(): @pytest.fixture def temp_output_file(): """Create temporary output file.""" - temp_file = tempfile.NamedTemporaryFile(suffix=".txt", delete=False) + temp_file = tempfile.NamedTemporaryFile(suffix=".txt", delete=False) # noqa: SIM115 yield temp_file.name # Cleanup os.remove(temp_file.name) diff --git a/scripts/tools/test/test_hdf5_to_mp4.py b/scripts/tools/test/test_hdf5_to_mp4.py index d013b32d2d9..33ccd0d1723 100644 --- a/scripts/tools/test/test_hdf5_to_mp4.py +++ b/scripts/tools/test/test_hdf5_to_mp4.py @@ -5,11 +5,12 @@ """Test cases for HDF5 to MP4 conversion script.""" +import os +import tempfile + import h5py import numpy as np -import os import pytest -import tempfile from scripts.tools.hdf5_to_mp4 import get_num_demos, main, write_demo_to_mp4 @@ -17,7 +18,7 @@ @pytest.fixture(scope="class") def temp_hdf5_file(): """Create temporary HDF5 file with test data.""" - temp_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=False) + temp_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=False) # noqa: SIM115 with h5py.File(temp_file.name, "w") as h5f: # Create test data structure for demo_id in range(2): # Create 2 demos @@ -47,7 +48,7 @@ def temp_hdf5_file(): @pytest.fixture def temp_output_dir(): """Create temporary output directory.""" - temp_dir = tempfile.mkdtemp() + temp_dir = tempfile.mkdtemp() # noqa: SIM115 yield temp_dir # Cleanup for file in os.listdir(temp_dir): diff --git a/scripts/tools/test/test_mp4_to_hdf5.py b/scripts/tools/test/test_mp4_to_hdf5.py index e6e1354ccde..631ac41da22 100644 --- a/scripts/tools/test/test_mp4_to_hdf5.py +++ b/scripts/tools/test/test_mp4_to_hdf5.py @@ -5,12 +5,13 @@ """Test cases for MP4 to HDF5 conversion script.""" +import os +import tempfile + import cv2 import h5py import numpy as np -import os import pytest -import tempfile from scripts.tools.mp4_to_hdf5 import get_frames_from_mp4, main, process_video_and_demo @@ -18,7 +19,7 @@ @pytest.fixture(scope="class") def temp_hdf5_file(): """Create temporary HDF5 file with test data.""" - temp_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=False) + temp_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=False) # noqa: SIM115 with h5py.File(temp_file.name, "w") as h5f: # Create test data structure for 2 demos for demo_id in range(2): @@ -54,7 +55,7 @@ def temp_hdf5_file(): @pytest.fixture(scope="class") def temp_videos_dir(): """Create temporary MP4 files.""" - temp_dir = tempfile.mkdtemp() + temp_dir = tempfile.mkdtemp() # noqa: SIM115 video_paths = [] for demo_id in range(2): @@ -82,7 +83,7 @@ def temp_videos_dir(): @pytest.fixture def temp_output_file(): """Create temporary output file.""" - temp_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=False) + temp_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=False) # noqa: SIM115 yield temp_file.name # Cleanup os.remove(temp_file.name) From 57796cfe9a2ca572983605a7f1e5473c023f0055 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:42:02 +0100 Subject: [PATCH 14/32] fixes space check --- source/isaaclab/isaaclab/envs/utils/spaces.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/isaaclab/isaaclab/envs/utils/spaces.py b/source/isaaclab/isaaclab/envs/utils/spaces.py index 9e7687d57e0..ae96c85ed6b 100644 --- a/source/isaaclab/isaaclab/envs/utils/spaces.py +++ b/source/isaaclab/isaaclab/envs/utils/spaces.py @@ -3,11 +3,12 @@ # # SPDX-License-Identifier: BSD-3-Clause -import gymnasium as gym import json +from typing import Any + +import gymnasium as gym import numpy as np import torch -from typing import Any from ..common import SpaceType @@ -61,7 +62,7 @@ def sample_space(space: gym.spaces.Space, device: str, batch_size: int = -1, fil Tensorized sampled space. """ - def tensorize(s, x): + def tensorize(s: gym.spaces.Space, x: Any) -> Any: if isinstance(s, gym.spaces.Box): tensor = torch.tensor(x, device=device, dtype=torch.float32).reshape(batch_size, *s.shape) if fill_value is not None: @@ -89,6 +90,9 @@ def tensorize(s, x): elif isinstance(s, gym.spaces.Tuple): return tuple([tensorize(_s, v) for _s, v in zip(s, x)]) + # If the space is not supported, raise an error + raise ValueError(f"Unsupported Gymnasium space for tensorization: {s}") + sample = (gym.vector.utils.batch_space(space, batch_size) if batch_size > 0 else space).sample() return tensorize(space, sample) From cdbaf769149b72c3f12876de5b9ec0c4e723c759 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:50:06 +0100 Subject: [PATCH 15/32] lint fixes --- scripts/demos/h1_locomotion.py | 1 + scripts/demos/pick_and_place.py | 5 ++++- .../isaaclab/ui/xr_widgets/scene_visualization.py | 2 +- source/isaaclab/isaaclab/utils/array.py | 3 +-- .../isaaclab_tasks/direct/factory/factory_control.py | 5 ++++- .../stack/config/galbot/stack_joint_pos_env_cfg.py | 8 +++----- .../manipulation/stack/mdp/observations.py | 7 ++++--- .../isaaclab_tasks/isaaclab_tasks/utils/importer.py | 12 ++++++++---- 8 files changed, 26 insertions(+), 17 deletions(-) diff --git a/scripts/demos/h1_locomotion.py b/scripts/demos/h1_locomotion.py index 0285fc4f07e..97c58af05b3 100644 --- a/scripts/demos/h1_locomotion.py +++ b/scripts/demos/h1_locomotion.py @@ -41,6 +41,7 @@ simulation_app = app_launcher.app """Rest everything follows.""" + import torch import carb diff --git a/scripts/demos/pick_and_place.py b/scripts/demos/pick_and_place.py index a652168c5a2..065881881cf 100644 --- a/scripts/demos/pick_and_place.py +++ b/scripts/demos/pick_and_place.py @@ -21,9 +21,12 @@ app_launcher = AppLauncher(args_cli) simulation_app = app_launcher.app -import torch +"""Rest everything follows.""" + from collections.abc import Sequence +import torch + import carb import omni diff --git a/source/isaaclab/isaaclab/ui/xr_widgets/scene_visualization.py b/source/isaaclab/isaaclab/ui/xr_widgets/scene_visualization.py index ddd3bda15ff..43cadbc3727 100644 --- a/source/isaaclab/isaaclab/ui/xr_widgets/scene_visualization.py +++ b/source/isaaclab/isaaclab/ui/xr_widgets/scene_visualization.py @@ -158,7 +158,7 @@ class VisualizationManager: # Type aliases for different callback signatures StandardCallback = Callable[["VisualizationManager", "DataCollector"], None] EventCallback = Callable[["VisualizationManager", "DataCollector", Any], None] - CallbackType = Union[StandardCallback, EventCallback] + CallbackType = Union[StandardCallback, EventCallback] # noqa: UP007 class TimeCountdown: """Internal class for managing periodic timer-based callbacks.""" diff --git a/source/isaaclab/isaaclab/utils/array.py b/source/isaaclab/isaaclab/utils/array.py index 7569c7b13f9..ef0b9555808 100644 --- a/source/isaaclab/isaaclab/utils/array.py +++ b/source/isaaclab/isaaclab/utils/array.py @@ -11,9 +11,8 @@ import numpy as np import torch import warp as wp -from typing import Union -TensorData = Union[np.ndarray, torch.Tensor, wp.array] +TensorData = Union[np.ndarray, torch.Tensor, wp.array] # noqa: UP007 """Type definition for a tensor data. Union of numpy, torch, and warp arrays. diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py b/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py index 6714f0d5b23..1facb42f0bc 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py @@ -9,6 +9,7 @@ """ import math + import torch import isaacsim.core.utils.torch as torch_utils @@ -142,6 +143,8 @@ def get_pose_error( return pos_error, quat_error elif rot_error_type == "axis_angle": return pos_error, axis_angle_error + else: + raise ValueError(f"Unsupported rotation error type: {rot_error_type}. Valid: 'quat', 'axis_angle'.") def get_delta_dof_pos(delta_pose, ik_method, jacobian, device): @@ -174,7 +177,7 @@ def get_delta_dof_pos(delta_pose, ik_method, jacobian, device): U, S, Vh = torch.linalg.svd(jacobian) S_inv = 1.0 / S min_singular_value = 1.0e-5 - S_inv = torch.where(S > min_singular_value, S_inv, torch.zeros_like(S_inv)) + S_inv = torch.where(min_singular_value < S, S_inv, torch.zeros_like(S_inv)) jacobian_pinv = ( torch.transpose(Vh, dim0=1, dim1=2)[:, :, :6] @ torch.diag_embed(S_inv) @ torch.transpose(U, dim0=1, dim1=2) ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/galbot/stack_joint_pos_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/galbot/stack_joint_pos_env_cfg.py index 57a438e4d6b..b0662275043 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/galbot/stack_joint_pos_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/galbot/stack_joint_pos_env_cfg.py @@ -277,11 +277,9 @@ def __post_init__(self): # post init of parent super().__post_init__() - l, r = self.events.randomize_cube_positions.params["pose_range"]["y"] - self.events.randomize_cube_positions.params["pose_range"]["y"] = ( - -r, - -l, - ) # move to area below right hand + # Move to area below right hand (invert y-axis) + left, right = self.events.randomize_cube_positions.params["pose_range"]["y"] + self.events.randomize_cube_positions.params["pose_range"]["y"] = (-right, -left) # Set actions for the specific robot type (galbot) self.actions.arm_action = mdp.JointPositionActionCfg( diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py index ef46bae7d3c..5da5a8a87aa 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py @@ -5,9 +5,10 @@ from __future__ import annotations -import torch from typing import TYPE_CHECKING, Literal +import torch + import isaaclab.utils.math as math_utils from isaaclab.assets import Articulation, RigidObject, RigidObjectCollection from isaaclab.managers import SceneEntityCfg @@ -434,7 +435,7 @@ def cube_poses_in_base_frame( return pos_cubes_base elif return_key == "quat": return quat_cubes_base - elif return_key is None: + else: return torch.cat((pos_cubes_base, quat_cubes_base), dim=1) @@ -528,5 +529,5 @@ def ee_frame_pose_in_base_frame( return ee_pos_in_base elif return_key == "quat": return ee_quat_in_base - elif return_key is None: + else: return torch.cat((ee_pos_in_base, ee_quat_in_base), dim=1) diff --git a/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py b/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py index bb4bb398029..7e284520913 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py +++ b/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py @@ -63,10 +63,12 @@ def _walk_packages( if blacklist_pkgs is None: blacklist_pkgs = [] - def seen(p, m={}): + def seen(p: str, m: dict[str, bool]) -> bool: + """Check if a package has been seen before.""" if p in m: return True - m[p] = True # noqa: R503 + m[p] = True + return False for info in pkgutil.iter_modules(path, prefix): # check blacklisted @@ -85,9 +87,11 @@ def seen(p, m={}): else: raise else: - path = getattr(sys.modules[info.name], "__path__", None) or [] + path = getattr(sys.modules[info.name], "__path__", None) or None + # create dictionary to store seen packages + m = {} # don't traverse path items we've seen before - path = [p for p in path if not seen(p)] + path = [p for p in path if not seen(p, m)] yield from _walk_packages(path, info.name + ".", onerror, blacklist_pkgs) From 09f1e0b91e0566e78ea448d9a6406b76d3f0829c Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:50:57 +0100 Subject: [PATCH 16/32] ff --- .../manager_based/manipulation/place/mdp/observations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/mdp/observations.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/mdp/observations.py index faf90330568..e0c89017e81 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/mdp/observations.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/place/mdp/observations.py @@ -41,7 +41,7 @@ def object_poses_in_base_frame( return pos_object_base elif return_key == "quat": return quat_object_base - elif return_key is None: + else: return torch.cat((pos_object_base, quat_object_base), dim=1) From 8395c8e78fead57c1ffa88ad6476d84a049d1cd5 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:54:14 +0100 Subject: [PATCH 17/32] other fixes from ruff --- docs/source/refs/snippets/code_skeleton.py | 2 -- .../vision_cartpole_cfg.py | 2 +- .../isaaclab/controllers/differential_ik.py | 2 +- .../isaaclab/ui/widgets/image_plot.py | 4 ++-- .../isaaclab_mimic/datagen/data_generator.py | 5 +---- .../direct/automate/factory_control.py | 4 +++- .../direct/automate/soft_dtw_cuda.py | 8 +++----- .../humanoid_amp/motions/motion_loader.py | 19 +++++++++---------- .../test/benchmarking/conftest.py | 2 +- 9 files changed, 21 insertions(+), 27 deletions(-) diff --git a/docs/source/refs/snippets/code_skeleton.py b/docs/source/refs/snippets/code_skeleton.py index ec9c057e726..0c3e456b330 100644 --- a/docs/source/refs/snippets/code_skeleton.py +++ b/docs/source/refs/snippets/code_skeleton.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -import os -import sys from typing import ClassVar diff --git a/scripts/reinforcement_learning/ray/hyperparameter_tuning/vision_cartpole_cfg.py b/scripts/reinforcement_learning/ray/hyperparameter_tuning/vision_cartpole_cfg.py index f48085134ee..f43ae7ecaaa 100644 --- a/scripts/reinforcement_learning/ray/hyperparameter_tuning/vision_cartpole_cfg.py +++ b/scripts/reinforcement_learning/ray/hyperparameter_tuning/vision_cartpole_cfg.py @@ -76,7 +76,7 @@ def __call__(self, trial_id: str, result: dict[str, Any]) -> bool: out_of_bounds = result.get("Episode/Episode_Termination/cart_out_of_bounds") # Mark the trial for stopping if conditions are met - if 20 <= iter and out_of_bounds is not None and out_of_bounds > 0.85: + if iter >= 20 and out_of_bounds is not None and out_of_bounds > 0.85: self._bad_trials.add(trial_id) return trial_id in self._bad_trials diff --git a/source/isaaclab/isaaclab/controllers/differential_ik.py b/source/isaaclab/isaaclab/controllers/differential_ik.py index bc43603c4be..1126f0c0cf3 100644 --- a/source/isaaclab/isaaclab/controllers/differential_ik.py +++ b/source/isaaclab/isaaclab/controllers/differential_ik.py @@ -209,7 +209,7 @@ def _compute_delta_joint_pos(self, delta_pose: torch.Tensor, jacobian: torch.Ten # U: 6xd, S: dxd, V: d x num-joint U, S, Vh = torch.linalg.svd(jacobian) S_inv = 1.0 / S - S_inv = torch.where(S > min_singular_value, S_inv, torch.zeros_like(S_inv)) + S_inv = torch.where(min_singular_value < S, S_inv, torch.zeros_like(S_inv)) jacobian_pinv = ( torch.transpose(Vh, dim0=1, dim1=2)[:, :, :6] @ torch.diag_embed(S_inv) diff --git a/source/isaaclab/isaaclab/ui/widgets/image_plot.py b/source/isaaclab/isaaclab/ui/widgets/image_plot.py index 8d8304e4a04..115a6f7f581 100644 --- a/source/isaaclab/isaaclab/ui/widgets/image_plot.py +++ b/source/isaaclab/isaaclab/ui/widgets/image_plot.py @@ -7,7 +7,7 @@ import numpy as np from contextlib import suppress from matplotlib import cm -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING import omni @@ -53,7 +53,7 @@ class ImagePlot(UIWidgetWrapper): def __init__( self, - image: Optional[np.ndarray] = None, + image: np.ndarray | None = None, label: str = "", widget_height: int = 200, min_value: float = 0.0, diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py index a6f85388424..7efaf52ae3c 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py @@ -187,10 +187,7 @@ def __repr__(self): Pretty print this object. """ msg = str(self.__class__.__name__) - msg += " (\n\tdataset_path={}\n\tdemo_keys={}\n)".format( - self.dataset_path, - self.demo_keys, - ) + msg += f" (\n\tdataset_path={self.dataset_path}\n\tdemo_keys={self.demo_keys}\n)" return msg def randomize_subtask_boundaries(self) -> dict[str, np.ndarray]: diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py index 58166eb9077..2bb44200654 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py @@ -132,6 +132,8 @@ def get_pose_error( return pos_error, quat_error elif rot_error_type == "axis_angle": return pos_error, axis_angle_error + else: + raise ValueError(f"Unsupported rotation error type: {rot_error_type}. Valid: 'quat', 'axis_angle'.") def _get_delta_dof_pos(delta_pose, ik_method, jacobian, device): @@ -164,7 +166,7 @@ def _get_delta_dof_pos(delta_pose, ik_method, jacobian, device): U, S, Vh = torch.linalg.svd(jacobian) S_inv = 1.0 / S min_singular_value = 1.0e-5 - S_inv = torch.where(S > min_singular_value, S_inv, torch.zeros_like(S_inv)) + S_inv = torch.where(min_singular_value < S, S_inv, torch.zeros_like(S_inv)) jacobian_pinv = ( torch.transpose(Vh, dim0=1, dim1=2)[:, :, :6] @ torch.diag_embed(S_inv) @ torch.transpose(U, dim0=1, dim1=2) ) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py index 12a4595654d..cee531d58a4 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py @@ -61,7 +61,7 @@ def compute_softdtw_cuda(D, gamma, bandwidth, max_i, max_j, n_passes, R): j = J + 1 # Only compute if element[i, j] is on the current anti-diagonal, and also is within bounds - if tid + J == p and (tid < max_i and J < max_j): + if tid + J == p and (tid < max_i and max_j > J): # Don't compute if outside bandwidth if not (abs(i - j) > bandwidth > 0): r0 = -R[b, i - 1, j - 1] * inv_gamma @@ -96,7 +96,7 @@ def compute_softdtw_backward_cuda(D, R, inv_gamma, bandwidth, max_i, max_j, n_pa j = J + 1 # Only compute if element[i, j] is on the current anti-diagonal, and also is within bounds - if tid + J == rev_p and (tid < max_i and J < max_j): + if tid + J == rev_p and (tid < max_i and max_j > J): if math.isinf(R[k, i, j]): R[k, i, j] = -math.inf @@ -403,9 +403,7 @@ def profile(batch_size, seq_len_a, seq_len_b, dims, tol_backward): n_iters = 6 print( - "Profiling forward() + backward() times for batch_size={}, seq_len_a={}, seq_len_b={}, dims={}...".format( - batch_size, seq_len_a, seq_len_b, dims - ) + f"Profiling forward() + backward() times for batch_size={batch_size}, seq_len_a={seq_len_a}, seq_len_b={seq_len_b}, dims={dims}..." ) times_cpu = [] diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py b/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py index 1ae9ea6ecf4..d81ae0d245c 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py @@ -6,7 +6,6 @@ import numpy as np import os import torch -from typing import Optional class MotionLoader: @@ -71,10 +70,10 @@ def _interpolate( self, a: torch.Tensor, *, - b: Optional[torch.Tensor] = None, - blend: Optional[torch.Tensor] = None, - start: Optional[np.ndarray] = None, - end: Optional[np.ndarray] = None, + b: torch.Tensor | None = None, + blend: torch.Tensor | None = None, + start: np.ndarray | None = None, + end: np.ndarray | None = None, ) -> torch.Tensor: """Linear interpolation between consecutive values. @@ -102,10 +101,10 @@ def _slerp( self, q0: torch.Tensor, *, - q1: Optional[torch.Tensor] = None, - blend: Optional[torch.Tensor] = None, - start: Optional[np.ndarray] = None, - end: Optional[np.ndarray] = None, + q1: torch.Tensor | None = None, + blend: torch.Tensor | None = None, + start: np.ndarray | None = None, + end: np.ndarray | None = None, ) -> torch.Tensor: """Interpolation between consecutive rotations (Spherical Linear Interpolation). @@ -196,7 +195,7 @@ def sample_times(self, num_samples: int, duration: float | None = None) -> np.nd return duration * np.random.uniform(low=0.0, high=1.0, size=num_samples) def sample( - self, num_samples: int, times: Optional[np.ndarray] = None, duration: float | None = None + self, num_samples: int, times: np.ndarray | None = None, duration: float | None = None ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """Sample motion data. diff --git a/source/isaaclab_tasks/test/benchmarking/conftest.py b/source/isaaclab_tasks/test/benchmarking/conftest.py index 50927383dcb..6a13b1898a5 100644 --- a/source/isaaclab_tasks/test/benchmarking/conftest.py +++ b/source/isaaclab_tasks/test/benchmarking/conftest.py @@ -7,7 +7,7 @@ import pytest -# Local imports should be imported last +# Local imports should be imported last import env_benchmark_test_utils as utils # isort: skip # Global variable for storing KPI data From 063d04dc1d7b3f67aa8c3ab40a2dd6370f771995 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 12:57:41 +0100 Subject: [PATCH 18/32] does other minor fixes --- pyproject.toml | 2 ++ source/isaaclab/isaaclab/envs/common.py | 2 +- source/isaaclab/isaaclab/utils/array.py | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index aa1cf45fb8e..f0fc4e750bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,8 @@ ignore = [ "SIM108", # Use ternary operator instead of if-else statement "SIM117", # Merge with statements for context managers "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() + "UP006", # Use 'dict' instead of 'Dict' type annotation + "UP018", # Unnecessary `float` call (rewrite as a literal) ] [tool.ruff.lint.per-file-ignores] diff --git a/source/isaaclab/isaaclab/envs/common.py b/source/isaaclab/isaaclab/envs/common.py index b6cc4c044fe..50597aa6383 100644 --- a/source/isaaclab/isaaclab/envs/common.py +++ b/source/isaaclab/isaaclab/envs/common.py @@ -7,7 +7,7 @@ import gymnasium as gym import torch -from typing import Dict, Literal, TypeVar +from typing import Dict, Literal, TypeVar # noqa: UP035 from isaaclab.utils import configclass diff --git a/source/isaaclab/isaaclab/utils/array.py b/source/isaaclab/isaaclab/utils/array.py index ef0b9555808..d15fbc275dc 100644 --- a/source/isaaclab/isaaclab/utils/array.py +++ b/source/isaaclab/isaaclab/utils/array.py @@ -8,6 +8,8 @@ # needed to import for allowing type-hinting: torch.device | str | None from __future__ import annotations +from typing import Union + import numpy as np import torch import warp as wp From e3cdc6075ece67f5cf86ba5140d59952910d6934 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:04:26 +0100 Subject: [PATCH 19/32] fix local import --- scripts/reinforcement_learning/ray/launch.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/reinforcement_learning/ray/launch.py b/scripts/reinforcement_learning/ray/launch.py index 453a6f65de5..68d086d3233 100644 --- a/scripts/reinforcement_learning/ray/launch.py +++ b/scripts/reinforcement_learning/ray/launch.py @@ -29,12 +29,14 @@ import argparse import pathlib import subprocess - -import util import yaml + from jinja2 import Environment, FileSystemLoader from kubernetes import config +# Local imports +import util # isort: skip + RAY_DIR = pathlib.Path(__file__).parent From 01a9d84d31f3915bb0ffddc4a67ec15e1ede5356 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:05:29 +0100 Subject: [PATCH 20/32] keeps isort import ordering --- scripts/demos/pick_and_place.py | 3 +-- scripts/tools/test/test_cosmos_prompt_gen.py | 3 +-- scripts/tools/test/test_hdf5_to_mp4.py | 5 ++--- scripts/tools/test/test_mp4_to_hdf5.py | 5 ++--- source/isaaclab/isaaclab/envs/utils/spaces.py | 5 ++--- source/isaaclab/isaaclab/utils/array.py | 3 +-- source/isaaclab/test/assets/test_rigid_object_collection.py | 1 - source/isaaclab/test/utils/test_configclass.py | 5 ++--- .../isaaclab_tasks/direct/factory/factory_control.py | 1 - .../manager_based/manipulation/stack/mdp/observations.py | 3 +-- source/isaaclab_tasks/test/benchmarking/conftest.py | 1 - source/isaaclab_tasks/test/test_record_video.py | 3 +-- tools/conftest.py | 6 +++--- 13 files changed, 16 insertions(+), 28 deletions(-) diff --git a/scripts/demos/pick_and_place.py b/scripts/demos/pick_and_place.py index 065881881cf..d3c22dc18a6 100644 --- a/scripts/demos/pick_and_place.py +++ b/scripts/demos/pick_and_place.py @@ -23,9 +23,8 @@ """Rest everything follows.""" -from collections.abc import Sequence - import torch +from collections.abc import Sequence import carb import omni diff --git a/scripts/tools/test/test_cosmos_prompt_gen.py b/scripts/tools/test/test_cosmos_prompt_gen.py index 17f1764d914..6f2f8d177a5 100644 --- a/scripts/tools/test/test_cosmos_prompt_gen.py +++ b/scripts/tools/test/test_cosmos_prompt_gen.py @@ -7,9 +7,8 @@ import json import os -import tempfile - import pytest +import tempfile from scripts.tools.cosmos.cosmos_prompt_gen import generate_prompt, main diff --git a/scripts/tools/test/test_hdf5_to_mp4.py b/scripts/tools/test/test_hdf5_to_mp4.py index 33ccd0d1723..0dc770e89a0 100644 --- a/scripts/tools/test/test_hdf5_to_mp4.py +++ b/scripts/tools/test/test_hdf5_to_mp4.py @@ -5,12 +5,11 @@ """Test cases for HDF5 to MP4 conversion script.""" -import os -import tempfile - import h5py import numpy as np +import os import pytest +import tempfile from scripts.tools.hdf5_to_mp4 import get_num_demos, main, write_demo_to_mp4 diff --git a/scripts/tools/test/test_mp4_to_hdf5.py b/scripts/tools/test/test_mp4_to_hdf5.py index 631ac41da22..6a8058d3be0 100644 --- a/scripts/tools/test/test_mp4_to_hdf5.py +++ b/scripts/tools/test/test_mp4_to_hdf5.py @@ -5,13 +5,12 @@ """Test cases for MP4 to HDF5 conversion script.""" -import os -import tempfile - import cv2 import h5py import numpy as np +import os import pytest +import tempfile from scripts.tools.mp4_to_hdf5 import get_frames_from_mp4, main, process_video_and_demo diff --git a/source/isaaclab/isaaclab/envs/utils/spaces.py b/source/isaaclab/isaaclab/envs/utils/spaces.py index ae96c85ed6b..27764e9f9b9 100644 --- a/source/isaaclab/isaaclab/envs/utils/spaces.py +++ b/source/isaaclab/isaaclab/envs/utils/spaces.py @@ -3,12 +3,11 @@ # # SPDX-License-Identifier: BSD-3-Clause -import json -from typing import Any - import gymnasium as gym +import json import numpy as np import torch +from typing import Any from ..common import SpaceType diff --git a/source/isaaclab/isaaclab/utils/array.py b/source/isaaclab/isaaclab/utils/array.py index d15fbc275dc..e26ff824dd9 100644 --- a/source/isaaclab/isaaclab/utils/array.py +++ b/source/isaaclab/isaaclab/utils/array.py @@ -8,11 +8,10 @@ # needed to import for allowing type-hinting: torch.device | str | None from __future__ import annotations -from typing import Union - import numpy as np import torch import warp as wp +from typing import Union TensorData = Union[np.ndarray, torch.Tensor, wp.array] # noqa: UP007 """Type definition for a tensor data. diff --git a/source/isaaclab/test/assets/test_rigid_object_collection.py b/source/isaaclab/test/assets/test_rigid_object_collection.py index d59daee84a7..ccce0e1bcb4 100644 --- a/source/isaaclab/test/assets/test_rigid_object_collection.py +++ b/source/isaaclab/test/assets/test_rigid_object_collection.py @@ -17,7 +17,6 @@ """Rest everything follows.""" import ctypes - import pytest import torch diff --git a/source/isaaclab/test/utils/test_configclass.py b/source/isaaclab/test/utils/test_configclass.py index 0c024be03f3..88fe192ef91 100644 --- a/source/isaaclab/test/utils/test_configclass.py +++ b/source/isaaclab/test/utils/test_configclass.py @@ -18,14 +18,13 @@ import copy import os +import pytest +import torch from collections.abc import Callable from dataclasses import MISSING, asdict, field from functools import wraps from typing import Any, ClassVar -import pytest -import torch - from isaaclab.utils.configclass import configclass from isaaclab.utils.dict import class_to_dict, dict_to_md5_hash, update_class_from_dict from isaaclab.utils.io import dump_yaml, load_yaml diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py b/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py index 1facb42f0bc..664c53b77cc 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/factory/factory_control.py @@ -9,7 +9,6 @@ """ import math - import torch import isaacsim.core.utils.torch as torch_utils diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py index 5da5a8a87aa..bb8dfd3aa58 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/mdp/observations.py @@ -5,9 +5,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Literal - import torch +from typing import TYPE_CHECKING, Literal import isaaclab.utils.math as math_utils from isaaclab.assets import Articulation, RigidObject, RigidObjectCollection diff --git a/source/isaaclab_tasks/test/benchmarking/conftest.py b/source/isaaclab_tasks/test/benchmarking/conftest.py index 6a13b1898a5..e4ef86d7dfd 100644 --- a/source/isaaclab_tasks/test/benchmarking/conftest.py +++ b/source/isaaclab_tasks/test/benchmarking/conftest.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: BSD-3-Clause import json - import pytest # Local imports should be imported last diff --git a/source/isaaclab_tasks/test/test_record_video.py b/source/isaaclab_tasks/test/test_record_video.py index a84eb846e88..e50c90093cd 100644 --- a/source/isaaclab_tasks/test/test_record_video.py +++ b/source/isaaclab_tasks/test/test_record_video.py @@ -13,9 +13,8 @@ """Rest everything follows.""" -import os - import gymnasium as gym +import os import pytest import torch diff --git a/tools/conftest.py b/tools/conftest.py index 52ae4023077..e89d2479ab1 100644 --- a/tools/conftest.py +++ b/tools/conftest.py @@ -5,6 +5,7 @@ import contextlib import os +import pytest # Platform-specific imports for real-time output streaming import select @@ -12,12 +13,11 @@ import sys import time -import pytest -from junitparser import Error, JUnitXml, TestCase, TestSuite - # Third-party imports from prettytable import PrettyTable +from junitparser import Error, JUnitXml, TestCase, TestSuite + import tools.test_settings as test_settings From cfda9ead07df102df94d64d39430ad36135122c2 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:05:39 +0100 Subject: [PATCH 21/32] uses isort for now --- .pre-commit-config.yaml | 9 ++++- pyproject.toml | 90 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 426a84b59b7..9e4f42025c0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,9 +9,14 @@ repos: hooks: # Run the linter - id: ruff - args: ["--fix"] + # args: ["--fix"] # Run the formatter - - id: ruff-format + # - id: ruff-format + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + name: isort (python) - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: diff --git a/pyproject.toml b/pyproject.toml index f0fc4e750bd..d871a8ef900 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes - "I", # isort + # "I", # isort "UP", # pyupgrade "C90", # mccabe complexity # "D", # pydocstyle @@ -95,6 +95,94 @@ section-order = [ "isaaclab-mimic" = ["isaaclab_mimic"] "isaaclab-tasks" = ["isaaclab_tasks"] +# TODO: Remove this once isort is removed from the project +[tool.isort] + +profile = "black" +py_version = 310 +line_length = 120 +group_by_package = true + +# Files to skip +skip_glob = ["docs/*", "logs/*", "_isaac_sim/*", ".vscode/*"] + +# Order of imports +sections = [ + "FUTURE", + "STDLIB", + "OMNIVERSE_EXTENSIONS", + "THIRDPARTY", + "ASSETS_FIRSTPARTY", + "FIRSTPARTY", + "EXTRA_FIRSTPARTY", + "TASK_FIRSTPARTY", + "LOCALFOLDER", +] + +# Extra standard libraries considered as part of python (permissive licenses +extra_standard_library = [ + "numpy", + "torch", + "einops", + "tensordict", + "warp", + "scipy", + "open3d", + "cv2", + "PIL", + "torchvision", + "transformers", + "h5py", + "yaml", + "toml", + "bpy", + "trimesh", + "matplotlib", + "gymnasium", + "gym", + "hid", + "prettytable", + "tqdm", + "flatdict", + "packaging", + "pytest", + "pytest-mock", + "flaky", +] + +known_third_party = [ + "junitparser", + "pinocchio", + "pink", + "rsl_rl", + "rl_games", + "ray", + "stable_baselines3", + "skrl", + "wandb", + "tensorboard", + "hydra", + "omegaconf", +] + +# Imports from Isaac Sim and Omniverse +known_omniverse_extensions = [ + "carb", + "omni*", + "isaacsim*", + "pxr", + "usdrt", + "Semantics", +] + +# Imports from this repository +known_first_party = "isaaclab" +known_assets_firstparty = "isaaclab_assets" +known_extra_firstparty = ["isaaclab_rl", "isaaclab_mimic"] +known_task_firstparty = "isaaclab_tasks" +# Imports from the local folder +known_local_folder = "config" + [tool.ruff.format] # Use Black-compatible formatting quote-style = "double" From 6c41331594a28870e798ce0a35a80f2298fd5691 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:06:04 +0100 Subject: [PATCH 22/32] enables ruff linter --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e4f42025c0..aad10d0ded5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: hooks: # Run the linter - id: ruff - # args: ["--fix"] + args: ["--fix"] # Run the formatter # - id: ruff-format - repo: https://github.com/pycqa/isort From e71d5f68a36c1f6f263a0a12df4be49fa036e67f Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:19:05 +0100 Subject: [PATCH 23/32] enter fixes --- pyproject.toml | 3 ++ .../isaaclab_mimic/generate_dataset.py | 1 - .../ray/grok_cluster_with_kubectl.py | 3 +- scripts/tools/merge_hdf5_datasets.py | 1 - scripts/tools/replay_demos.py | 4 +- .../tools/train_and_publish_checkpoints.py | 3 -- .../isaaclab/actuators/actuator_cfg.py | 3 +- .../isaaclab/devices/openxr/openxr_device.py | 1 + .../isaaclab/devices/teleop_device_factory.py | 1 + .../isaaclab/isaaclab/envs/mimic_env_cfg.py | 1 + .../isaaclab/envs/utils/io_descriptors.py | 1 - .../multi_mesh_ray_caster_camera_data.py | 1 + .../ray_caster/multi_mesh_ray_caster_cfg.py | 1 - .../ray_caster/multi_mesh_ray_caster_data.py | 1 + .../sensors/ray_caster/ray_caster_cfg.py | 1 - .../isaaclab/ui/widgets/image_plot.py | 1 - .../isaaclab/isaaclab/ui/widgets/line_plot.py | 1 - .../isaaclab/isaaclab/utils/warp/kernels.py | 2 - .../isaaclab/test/assets/test_rigid_object.py | 2 - .../test/controllers/test_local_frame_task.py | 1 + .../test_null_space_posture_task.py | 37 ++++++++--------- .../controllers/test_operational_space.py | 20 +++++++++- .../isaaclab/test/controllers/test_pink_ik.py | 13 +++--- .../controllers/test_pink_ik_components.py | 1 + .../test/managers/test_event_manager.py | 1 + .../test/sensors/test_visuotactile_render.py | 1 + .../isaaclab_assets/robots/allegro.py | 1 - .../robots/cart_double_pendulum.py | 1 - .../isaaclab_assets/robots/cartpole.py | 1 - .../isaaclab_assets/robots/franka.py | 1 - .../isaaclab_assets/robots/shadow_hand.py | 1 - .../isaaclab_assets/sensors/velodyne.py | 1 - .../isaaclab_mimic/datagen/data_generator.py | 25 ++++++------ .../isaaclab_mimic/datagen/datagen_info.py | 1 + .../isaaclab_mimic/datagen/generation.py | 1 - .../datagen/selection_strategy.py | 1 + .../isaaclab_mimic/datagen/waypoint.py | 1 + .../franka_bin_stack_ik_rel_mimic_env_cfg.py | 1 - .../direct/automate/factory_control.py | 4 +- .../direct/automate/industreal_algo_utils.py | 1 - .../direct/automate/soft_dtw_cuda.py | 5 --- .../direct/cartpole/cartpole_camera_env.py | 1 - .../cartpole/cartpole_env.py | 1 - .../classic/humanoid/agents/rsl_rl_ppo_cfg.py | 1 - .../manipulation/deploy/mdp/events.py | 1 - .../manipulation/inhand/mdp/events.py | 1 - .../isaaclab_tasks/utils/hydra.py | 1 - .../isaaclab_tasks/test/test_environments.py | 1 + .../test/test_factory_environments.py | 1 + .../test/test_lift_teddy_bear.py | 1 + .../test/test_rl_device_separation.py | 36 ++++++++--------- tools/template/cli.py | 2 +- tools/template/generator.py | 40 ++++++++++--------- 53 files changed, 124 insertions(+), 115 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d871a8ef900..a2b0e0a188d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -189,6 +189,9 @@ quote-style = "double" indent-style = "space" skip-magic-trailing-comma = false line-ending = "auto" +preview = true + +# docstring-code-format = true [tool.pyright] diff --git a/scripts/imitation_learning/isaaclab_mimic/generate_dataset.py b/scripts/imitation_learning/isaaclab_mimic/generate_dataset.py index 3f83fa171ee..3c700e97df6 100644 --- a/scripts/imitation_learning/isaaclab_mimic/generate_dataset.py +++ b/scripts/imitation_learning/isaaclab_mimic/generate_dataset.py @@ -7,7 +7,6 @@ Main data generation script. """ - """Launch Isaac Sim Simulator first.""" import argparse diff --git a/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py b/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py index 0692bd22d49..bd86d4bd223 100644 --- a/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py +++ b/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py @@ -30,7 +30,8 @@ def get_namespace() -> str: """Get the current Kubernetes namespace from the context, fallback to default if not set""" try: namespace = ( - subprocess.check_output(["kubectl", "config", "view", "--minify", "--output", "jsonpath={..namespace}"]) + subprocess + .check_output(["kubectl", "config", "view", "--minify", "--output", "jsonpath={..namespace}"]) .decode() .strip() ) diff --git a/scripts/tools/merge_hdf5_datasets.py b/scripts/tools/merge_hdf5_datasets.py index e29db100e2e..e38555dcb11 100644 --- a/scripts/tools/merge_hdf5_datasets.py +++ b/scripts/tools/merge_hdf5_datasets.py @@ -30,7 +30,6 @@ def merge_datasets(): copy_attributes = True for filepath in args_cli.input_files: - with h5py.File(filepath, "r") as input: for episode, data in input["data"].items(): input.copy(f"data/{episode}", output, f"data/demo_{episode_idx}") diff --git a/scripts/tools/replay_demos.py b/scripts/tools/replay_demos.py index 680d75deea5..de0582045cb 100644 --- a/scripts/tools/replay_demos.py +++ b/scripts/tools/replay_demos.py @@ -250,7 +250,7 @@ def main(): if next_episode_index is not None: replayed_episode_count += 1 current_episode_indices[env_id] = next_episode_index - print(f"{replayed_episode_count :4}: Loading #{next_episode_index} episode to env_{env_id}") + print(f"{replayed_episode_count:4}: Loading #{next_episode_index} episode to env_{env_id}") episode_data = dataset_file_handler.load_episode( episode_names[next_episode_index], env.device ) @@ -278,7 +278,7 @@ def main(): state_from_dataset = env_episode_data_map[0].get_next_state() if state_from_dataset is not None: print( - f"Validating states at action-index: {env_episode_data_map[0].next_state_index - 1 :4}", + f"Validating states at action-index: {env_episode_data_map[0].next_state_index - 1:4}", end="", ) current_runtime_state = env.scene.get_state(is_relative=True) diff --git a/scripts/tools/train_and_publish_checkpoints.py b/scripts/tools/train_and_publish_checkpoints.py index 71083dc2e4b..94f26efca2f 100644 --- a/scripts/tools/train_and_publish_checkpoints.py +++ b/scripts/tools/train_and_publish_checkpoints.py @@ -317,7 +317,6 @@ def publish_pretrained_checkpoint(workflow, task_name, force_publish=False): # Not forcing, need to check review results if not force_publish: - # Grab the review if it exists review = get_pretrained_checkpoint_review(workflow, task_name) @@ -355,7 +354,6 @@ def get_job_summary_row(workflow, task_name): def main(): - # Figure out what workflows and tasks we'll be using if args.all: jobs = ["*:*"] @@ -405,7 +403,6 @@ def main(): if __name__ == "__main__": - try: # Run the main function main() diff --git a/source/isaaclab/isaaclab/actuators/actuator_cfg.py b/source/isaaclab/isaaclab/actuators/actuator_cfg.py index c665a222980..5cacb8ffa40 100644 --- a/source/isaaclab/isaaclab/actuators/actuator_cfg.py +++ b/source/isaaclab/isaaclab/actuators/actuator_cfg.py @@ -21,8 +21,7 @@ def __getattr__(name): if new_module is not None: warnings.warn( f"The module actuator_cfg.py is deprecated. Please import {name} directly from the isaaclab.actuators" - " package, " - + f"or from its new module {new_module.__name__}.", + f" package, or from its new module {new_module.__name__}.", DeprecationWarning, stacklevel=2, ) diff --git a/source/isaaclab/isaaclab/devices/openxr/openxr_device.py b/source/isaaclab/isaaclab/devices/openxr/openxr_device.py index 02961040314..e51c25ae1bb 100644 --- a/source/isaaclab/isaaclab/devices/openxr/openxr_device.py +++ b/source/isaaclab/isaaclab/devices/openxr/openxr_device.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """OpenXR-powered device for teleoperation and interaction.""" + from __future__ import annotations import contextlib diff --git a/source/isaaclab/isaaclab/devices/teleop_device_factory.py b/source/isaaclab/isaaclab/devices/teleop_device_factory.py index 5f2d393ac69..f7265c41c2c 100644 --- a/source/isaaclab/isaaclab/devices/teleop_device_factory.py +++ b/source/isaaclab/isaaclab/devices/teleop_device_factory.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """Factory to create teleoperation devices from configuration.""" + import inspect import logging from collections.abc import Callable diff --git a/source/isaaclab/isaaclab/envs/mimic_env_cfg.py b/source/isaaclab/isaaclab/envs/mimic_env_cfg.py index d6dced3bbc9..c2b0f22efc0 100644 --- a/source/isaaclab/isaaclab/envs/mimic_env_cfg.py +++ b/source/isaaclab/isaaclab/envs/mimic_env_cfg.py @@ -9,6 +9,7 @@ """ Base MimicEnvCfg object for Isaac Lab Mimic data generation. """ + import enum from isaaclab.managers.recorder_manager import RecorderManagerBaseCfg diff --git a/source/isaaclab/isaaclab/envs/utils/io_descriptors.py b/source/isaaclab/isaaclab/envs/utils/io_descriptors.py index ae92c31062a..87ec1b450cf 100644 --- a/source/isaaclab/isaaclab/envs/utils/io_descriptors.py +++ b/source/isaaclab/isaaclab/envs/utils/io_descriptors.py @@ -185,7 +185,6 @@ def my_func(env: ManagerBasedEnv, *args, **kwargs): inspect_hooks: list[Callable[..., Any]] = list(on_inspect or []) # handles None def _apply(func: Callable[Concatenate[ManagerBasedEnv, P], R]) -> Callable[Concatenate[ManagerBasedEnv, P], R]: - # Capture the signature of the function sig = inspect.signature(func) diff --git a/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_camera_data.py b/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_camera_data.py index d00dab7edf1..d2f26abdbf4 100644 --- a/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_camera_data.py +++ b/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_camera_data.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """Data container for the multi-mesh ray-cast camera sensor.""" + import torch from isaaclab.sensors.camera import CameraData diff --git a/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_cfg.py b/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_cfg.py index 2030a894fda..507e2dfabbe 100644 --- a/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_cfg.py +++ b/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_cfg.py @@ -6,7 +6,6 @@ """Configuration for the ray-cast sensor.""" - from dataclasses import MISSING from isaaclab.utils import configclass diff --git a/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_data.py b/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_data.py index d37c49838bb..b9ae187591b 100644 --- a/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_data.py +++ b/source/isaaclab/isaaclab/sensors/ray_caster/multi_mesh_ray_caster_data.py @@ -5,6 +5,7 @@ """Data container for the multi-mesh ray-cast sensor.""" + import torch from .ray_caster_data import RayCasterData diff --git a/source/isaaclab/isaaclab/sensors/ray_caster/ray_caster_cfg.py b/source/isaaclab/isaaclab/sensors/ray_caster/ray_caster_cfg.py index 851ac31c85b..1ce3b0c43a9 100644 --- a/source/isaaclab/isaaclab/sensors/ray_caster/ray_caster_cfg.py +++ b/source/isaaclab/isaaclab/sensors/ray_caster/ray_caster_cfg.py @@ -5,7 +5,6 @@ """Configuration for the ray-cast sensor.""" - from dataclasses import MISSING from typing import Literal diff --git a/source/isaaclab/isaaclab/ui/widgets/image_plot.py b/source/isaaclab/isaaclab/ui/widgets/image_plot.py index 115a6f7f581..8ca25144135 100644 --- a/source/isaaclab/isaaclab/ui/widgets/image_plot.py +++ b/source/isaaclab/isaaclab/ui/widgets/image_plot.py @@ -156,7 +156,6 @@ def _get_unit_description(self, min_value: float, max_value: float, median_value ) def _build_widget(self): - with omni.ui.VStack(spacing=3): with omni.ui.HStack(): # Write the leftmost label for what this plot is diff --git a/source/isaaclab/isaaclab/ui/widgets/line_plot.py b/source/isaaclab/isaaclab/ui/widgets/line_plot.py index 90a84e201a1..0768115f97f 100644 --- a/source/isaaclab/isaaclab/ui/widgets/line_plot.py +++ b/source/isaaclab/isaaclab/ui/widgets/line_plot.py @@ -157,7 +157,6 @@ def add_datapoint(self, y_coords: list[float]): """ for idx, y_coord in enumerate(y_coords): - if len(self._y_data[idx]) > self._max_data_points: self._y_data[idx] = self._y_data[idx][1:] diff --git a/source/isaaclab/isaaclab/utils/warp/kernels.py b/source/isaaclab/isaaclab/utils/warp/kernels.py index faab41267a5..a37b647f235 100644 --- a/source/isaaclab/isaaclab/utils/warp/kernels.py +++ b/source/isaaclab/isaaclab/utils/warp/kernels.py @@ -135,7 +135,6 @@ def raycast_static_meshes_kernel( # if the ray hit, store the hit data if mesh_query_ray_t.result: - wp.atomic_min(ray_distance, tid_env, tid_ray, mesh_query_ray_t.t) # check if hit distance is less than the current hit distance, only then update the memory # TODO, in theory we could use the output of atomic_min to avoid the non-thread safe next comparison @@ -220,7 +219,6 @@ def raycast_dynamic_meshes_kernel( mesh_query_ray_t = wp.mesh_query_ray(mesh[tid_env, tid_mesh_id], start_pos, direction, max_dist) # if the ray hit, store the hit data if mesh_query_ray_t.result: - wp.atomic_min(ray_distance, tid_env, tid_ray, mesh_query_ray_t.t) # check if hit distance is less than the current hit distance, only then update the memory # TODO, in theory we could use the output of atomic_min to avoid the non-thread safe next comparison diff --git a/source/isaaclab/test/assets/test_rigid_object.py b/source/isaaclab/test/assets/test_rigid_object.py index 3a4d34847e5..2d6574725b9 100644 --- a/source/isaaclab/test/assets/test_rigid_object.py +++ b/source/isaaclab/test/assets/test_rigid_object.py @@ -225,7 +225,6 @@ def test_external_force_buffer(device): # perform simulation for step in range(5): - # initiate force tensor external_wrench_b = torch.zeros(cube_object.num_instances, len(body_ids), 6, device=sim.device) external_wrench_positions_b = torch.zeros(cube_object.num_instances, len(body_ids), 3, device=sim.device) @@ -997,7 +996,6 @@ def test_write_root_state(num_cubes, device, with_offset, state_location): env_idx = env_idx.to(device) for i in range(10): - # perform step sim.step() # update buffers diff --git a/source/isaaclab/test/controllers/test_local_frame_task.py b/source/isaaclab/test/controllers/test_local_frame_task.py index eec4ed2ab61..c60db228a34 100644 --- a/source/isaaclab/test/controllers/test_local_frame_task.py +++ b/source/isaaclab/test/controllers/test_local_frame_task.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """Test cases for LocalFrameTask class.""" + # Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim # pinocchio is required by the Pink IK controller import sys diff --git a/source/isaaclab/test/controllers/test_null_space_posture_task.py b/source/isaaclab/test/controllers/test_null_space_posture_task.py index 2d3be6159cd..66db14e9508 100644 --- a/source/isaaclab/test/controllers/test_null_space_posture_task.py +++ b/source/isaaclab/test/controllers/test_null_space_posture_task.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: BSD-3-Clause """Launch Isaac Sim Simulator first.""" + # Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim # pinocchio is required by the Pink IK controller import sys @@ -150,9 +151,9 @@ def test_null_space_jacobian_properties(self, robot_configuration, tasks, joint_ # Test: N * J^T should be approximately zero (null space property) # where N is the null space projector and J is the end-effector Jacobian null_space_projection = null_space_jacobian @ ee_jacobian.T - assert np.allclose( - null_space_projection, np.zeros_like(null_space_projection), atol=1e-7 - ), f"Null space projection of end-effector Jacobian not zero: {null_space_projection}" + assert np.allclose(null_space_projection, np.zeros_like(null_space_projection), atol=1e-7), ( + f"Null space projection of end-effector Jacobian not zero: {null_space_projection}" + ) def test_null_space_jacobian_identity_when_no_frame_tasks( self, robot_configuration, joint_configurations, num_joints @@ -173,9 +174,9 @@ def test_null_space_jacobian_identity_when_no_frame_tasks( # Should be identity matrix expected_identity = np.eye(num_joints) - assert np.allclose( - null_space_jacobian, expected_identity - ), f"Null space Jacobian should be identity when no frame tasks defined: {null_space_jacobian}" + assert np.allclose(null_space_jacobian, expected_identity), ( + f"Null space Jacobian should be identity when no frame tasks defined: {null_space_jacobian}" + ) def test_null_space_jacobian_consistency_across_configurations( self, robot_configuration, tasks, joint_configurations, num_joints @@ -215,9 +216,9 @@ def test_null_space_jacobian_consistency_across_configurations( null_space_velocity = jacobian @ random_velocity ee_velocity = ee_jacobian @ null_space_velocity - assert np.allclose( - ee_velocity, np.zeros(6), atol=1e-7 - ), f"End-effector velocity not zero for configuration {config}: {ee_velocity}" + assert np.allclose(ee_velocity, np.zeros(6), atol=1e-7), ( + f"End-effector velocity not zero for configuration {config}: {ee_velocity}" + ) def test_compute_error_without_target(self, robot_configuration, joint_configurations): """Test that compute_error raises ValueError when no target is set.""" @@ -263,9 +264,9 @@ def test_joint_masking(self, robot_configuration, joint_configurations, num_join for i in joint_indexes: expected_error[i] = current_config[i] - assert np.allclose( - error, expected_error, atol=1e-7 - ), f"Joint mask not working correctly: expected {expected_error}, got {error}" + assert np.allclose(error, expected_error, atol=1e-7), ( + f"Joint mask not working correctly: expected {expected_error}, got {error}" + ) def test_empty_controlled_joints(self, robot_configuration, joint_configurations, num_joints): """Test behavior when controlled_joints is empty.""" @@ -331,9 +332,9 @@ def test_multiple_frame_tasks(self, robot_configuration, joint_configurations, n ee_velocity_left = jacobian_left_hand @ null_space_velocity ee_velocity_right = jacobian_right_hand @ null_space_velocity - assert np.allclose( - ee_velocity_left, np.zeros(6), atol=1e-7 - ), f"Left hand velocity not zero: {ee_velocity_left}" - assert np.allclose( - ee_velocity_right, np.zeros(6), atol=1e-7 - ), f"Right hand velocity not zero: {ee_velocity_right}" + assert np.allclose(ee_velocity_left, np.zeros(6), atol=1e-7), ( + f"Left hand velocity not zero: {ee_velocity_left}" + ) + assert np.allclose(ee_velocity_right, np.zeros(6), atol=1e-7), ( + f"Right hand velocity not zero: {ee_velocity_right}" + ) diff --git a/source/isaaclab/test/controllers/test_operational_space.py b/source/isaaclab/test/controllers/test_operational_space.py index 2533eaeeb59..eeec14d877d 100644 --- a/source/isaaclab/test/controllers/test_operational_space.py +++ b/source/isaaclab/test/controllers/test_operational_space.py @@ -198,7 +198,25 @@ def sim(): # Reference frame for targets frame = "root" - yield sim, num_envs, robot_cfg, ee_marker, goal_marker, contact_forces, target_abs_pos_set_b, target_abs_pose_set_b, target_rel_pos_set, target_rel_pose_set_b, target_abs_wrench_set, target_abs_pose_variable_kp_set, target_abs_pose_variable_set, target_hybrid_set_b, target_hybrid_variable_kp_set, target_hybrid_set_tilted, frame + yield ( + sim, + num_envs, + robot_cfg, + ee_marker, + goal_marker, + contact_forces, + target_abs_pos_set_b, + target_abs_pose_set_b, + target_rel_pos_set, + target_rel_pose_set_b, + target_abs_wrench_set, + target_abs_pose_variable_kp_set, + target_abs_pose_variable_set, + target_hybrid_set_b, + target_hybrid_variable_kp_set, + target_hybrid_set_tilted, + frame, + ) # Cleanup sim.stop() diff --git a/source/isaaclab/test/controllers/test_pink_ik.py b/source/isaaclab/test/controllers/test_pink_ik.py index e16e0a0f549..8d7ee7c6f67 100644 --- a/source/isaaclab/test/controllers/test_pink_ik.py +++ b/source/isaaclab/test/controllers/test_pink_ik.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """Launch Isaac Sim Simulator first.""" + # Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim # pinocchio is required by the Pink IK controller import sys @@ -111,9 +112,9 @@ def env_and_cfg(request): # Try to infer which is left and which is right left_candidates = [f for f in frames if "left" in f.lower()] right_candidates = [f for f in frames if "right" in f.lower()] - assert ( - len(left_candidates) == 1 and len(right_candidates) == 1 - ), f"Could not uniquely identify left/right frames from: {frames}" + assert len(left_candidates) == 1 and len(right_candidates) == 1, ( + f"Could not uniquely identify left/right frames from: {frames}" + ) left_eef_urdf_link_name = left_candidates[0] right_eef_urdf_link_name = right_candidates[0] @@ -366,12 +367,14 @@ def compute_errors( # Calculate PD errors left_pd_error = ( - torch.tensor(left_target_pos - left_curr_pos, device=device, dtype=torch.float32) + torch + .tensor(left_target_pos - left_curr_pos, device=device, dtype=torch.float32) .unsqueeze(0) .repeat(num_envs, 1) ) right_pd_error = ( - torch.tensor(right_target_pos - right_curr_pos, device=device, dtype=torch.float32) + torch + .tensor(right_target_pos - right_curr_pos, device=device, dtype=torch.float32) .unsqueeze(0) .repeat(num_envs, 1) ) diff --git a/source/isaaclab/test/controllers/test_pink_ik_components.py b/source/isaaclab/test/controllers/test_pink_ik_components.py index 36bbea8ca31..7b06516724a 100644 --- a/source/isaaclab/test/controllers/test_pink_ik_components.py +++ b/source/isaaclab/test/controllers/test_pink_ik_components.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """Test cases for PinkKinematicsConfiguration class.""" + # Import pinocchio in the main script to force the use of the dependencies installed by IsaacLab and not the one installed by Isaac Sim # pinocchio is required by the Pink IK controller import sys diff --git a/source/isaaclab/test/managers/test_event_manager.py b/source/isaaclab/test/managers/test_event_manager.py index 64cba01564f..7a5aa0b652d 100644 --- a/source/isaaclab/test/managers/test_event_manager.py +++ b/source/isaaclab/test/managers/test_event_manager.py @@ -7,6 +7,7 @@ # pyright: reportPrivateUsage=none """Launch Isaac Sim Simulator first.""" + from collections.abc import Sequence from isaaclab.app import AppLauncher diff --git a/source/isaaclab/test/sensors/test_visuotactile_render.py b/source/isaaclab/test/sensors/test_visuotactile_render.py index b152ecc7497..2fb490033ae 100644 --- a/source/isaaclab/test/sensors/test_visuotactile_render.py +++ b/source/isaaclab/test/sensors/test_visuotactile_render.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause """Tests for GelSight utility functions - primarily focused on GelsightRender.""" + """Launch Isaac Sim Simulator first.""" from isaaclab.app import AppLauncher diff --git a/source/isaaclab_assets/isaaclab_assets/robots/allegro.py b/source/isaaclab_assets/isaaclab_assets/robots/allegro.py index 7720d324a81..0e18ef77c13 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/allegro.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/allegro.py @@ -15,7 +15,6 @@ """ - import math import isaaclab.sim as sim_utils diff --git a/source/isaaclab_assets/isaaclab_assets/robots/cart_double_pendulum.py b/source/isaaclab_assets/isaaclab_assets/robots/cart_double_pendulum.py index 6ab01086f6f..22028f39baf 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/cart_double_pendulum.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/cart_double_pendulum.py @@ -5,7 +5,6 @@ """Configuration for a simple inverted Double Pendulum on a Cart robot.""" - import isaaclab.sim as sim_utils from isaaclab.actuators import ImplicitActuatorCfg from isaaclab.assets import ArticulationCfg diff --git a/source/isaaclab_assets/isaaclab_assets/robots/cartpole.py b/source/isaaclab_assets/isaaclab_assets/robots/cartpole.py index 7813c019534..1e236eda6b9 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/cartpole.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/cartpole.py @@ -5,7 +5,6 @@ """Configuration for a simple Cartpole robot.""" - import isaaclab.sim as sim_utils from isaaclab.actuators import ImplicitActuatorCfg from isaaclab.assets import ArticulationCfg diff --git a/source/isaaclab_assets/isaaclab_assets/robots/franka.py b/source/isaaclab_assets/isaaclab_assets/robots/franka.py index 62d46338c18..caacf214c58 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/franka.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/franka.py @@ -14,7 +14,6 @@ Reference: https://github.com/frankaemika/franka_ros """ - import isaaclab.sim as sim_utils from isaaclab.actuators import ImplicitActuatorCfg from isaaclab.assets.articulation import ArticulationCfg diff --git a/source/isaaclab_assets/isaaclab_assets/robots/shadow_hand.py b/source/isaaclab_assets/isaaclab_assets/robots/shadow_hand.py index 2e0bd54ee8f..d13e90e3b1c 100644 --- a/source/isaaclab_assets/isaaclab_assets/robots/shadow_hand.py +++ b/source/isaaclab_assets/isaaclab_assets/robots/shadow_hand.py @@ -15,7 +15,6 @@ """ - import isaaclab.sim as sim_utils from isaaclab.actuators import ImplicitActuatorCfg from isaaclab.assets.articulation import ArticulationCfg diff --git a/source/isaaclab_assets/isaaclab_assets/sensors/velodyne.py b/source/isaaclab_assets/isaaclab_assets/sensors/velodyne.py index 5ecfa42700e..6cd075f4fa2 100644 --- a/source/isaaclab_assets/isaaclab_assets/sensors/velodyne.py +++ b/source/isaaclab_assets/isaaclab_assets/sensors/velodyne.py @@ -5,7 +5,6 @@ """Configuration for Velodyne LiDAR sensors.""" - from isaaclab.sensors import RayCasterCfg, patterns ## diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py index 7efaf52ae3c..338b4dc03be 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py @@ -6,6 +6,7 @@ """ Base class for data generator. """ + import asyncio import copy import logging @@ -238,9 +239,9 @@ def randomize_subtask_boundaries(self) -> dict[str, np.ndarray]: assert np.all((subtask_boundaries[:, :, 1] - subtask_boundaries[:, :, 0]) > 0), "got empty subtasks!" # Ensure subtask indices increase (both starts and ends) - assert np.all( - (subtask_boundaries[:, 1:, :] - subtask_boundaries[:, :-1, :]) > 0 - ), "subtask indices do not strictly increase" + assert np.all((subtask_boundaries[:, 1:, :] - subtask_boundaries[:, :-1, :]) > 0), ( + "subtask indices do not strictly increase" + ) # Ensure subtasks are in order subtask_inds_flat = subtask_boundaries.reshape(subtask_boundaries.shape[0], -1) @@ -408,17 +409,17 @@ def generate_eef_subtask_trajectory( (concurrent_task_spec_key, concurrent_subtask_ind) ]["transform"] else: - assert ( - "transform" not in runtime_subtask_constraints_dict[(eef_name, subtask_ind)] - ), "transform should not be set for concurrent task" + assert "transform" not in runtime_subtask_constraints_dict[(eef_name, subtask_ind)], ( + "transform should not be set for concurrent task" + ) # Need to transform demo according to scheme coord_transform_scheme = runtime_subtask_constraints_dict[(eef_name, subtask_ind)][ "coordination_scheme" ] if coord_transform_scheme != SubTaskConstraintCoordinationScheme.REPLAY: - assert ( - subtask_object_name is not None - ), f"object reference should not be None for {coord_transform_scheme} coordination scheme" + assert subtask_object_name is not None, ( + f"object reference should not be None for {coord_transform_scheme} coordination scheme" + ) if need_source_demo_selection: selected_src_demo_inds[eef_name] = self.select_source_demo( @@ -444,9 +445,9 @@ def generate_eef_subtask_trajectory( if (eef_name, subtask_ind) in runtime_subtask_constraints_dict: if runtime_subtask_constraints_dict[(eef_name, subtask_ind)]["type"] == SubTaskConstraintType.COORDINATION: # Store selected source demo ind for concurrent task - runtime_subtask_constraints_dict[(eef_name, subtask_ind)][ - "selected_src_demo_ind" - ] = selected_src_demo_ind + runtime_subtask_constraints_dict[(eef_name, subtask_ind)]["selected_src_demo_ind"] = ( + selected_src_demo_ind + ) concurrent_task_spec_key = runtime_subtask_constraints_dict[(eef_name, subtask_ind)][ "concurrent_task_spec_key" ] diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/datagen_info.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/datagen_info.py index 18036ea1cf5..e68d70ed952 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/datagen_info.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/datagen_info.py @@ -6,6 +6,7 @@ """ Defines structure of information that is needed from an environment for data generation. """ + from copy import deepcopy diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/generation.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/generation.py index 784a563cd64..b1f45ab00b0 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/generation.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/generation.py @@ -93,7 +93,6 @@ def env_loop( # simulate environment -- run everything in inference mode with contextlib.suppress(KeyboardInterrupt) and torch.inference_mode(): while True: - # check if any environment needs to be reset while waiting for actions while env_action_queue.qsize() != env.num_envs: asyncio_event_loop.run_until_complete(asyncio.sleep(0)) diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/selection_strategy.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/selection_strategy.py index 9028febbd42..dc773215b44 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/selection_strategy.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/selection_strategy.py @@ -7,6 +7,7 @@ Selection strategies used by Isaac Lab Mimic to select subtask segments from source human demonstrations. """ + import abc # for abstract base class definitions import torch diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/waypoint.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/waypoint.py index 2996e616151..77b7447acff 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/waypoint.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/waypoint.py @@ -6,6 +6,7 @@ """ A collection of classes used to represent waypoints and trajectories. """ + import asyncio import inspect import torch diff --git a/source/isaaclab_mimic/isaaclab_mimic/envs/franka_bin_stack_ik_rel_mimic_env_cfg.py b/source/isaaclab_mimic/isaaclab_mimic/envs/franka_bin_stack_ik_rel_mimic_env_cfg.py index fdc38c55b85..ca28719d730 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/envs/franka_bin_stack_ik_rel_mimic_env_cfg.py +++ b/source/isaaclab_mimic/isaaclab_mimic/envs/franka_bin_stack_ik_rel_mimic_env_cfg.py @@ -16,7 +16,6 @@ class FrankaBinStackIKRelMimicEnvCfg(FrankaBinStackEnvCfg, MimicEnvCfg): """ def __post_init__(self): - # post init of parents super().__post_init__() diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py index 2bb44200654..6cd797e7d6d 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py @@ -117,9 +117,7 @@ def get_pose_error( fingertip_midpoint_quat_norm = torch_utils.quat_mul( fingertip_midpoint_quat, torch_utils.quat_conjugate(fingertip_midpoint_quat) - )[ - :, 0 - ] # scalar component + )[:, 0] # scalar component fingertip_midpoint_quat_inv = torch_utils.quat_conjugate( fingertip_midpoint_quat ) / fingertip_midpoint_quat_norm.unsqueeze(-1) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/industreal_algo_utils.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/industreal_algo_utils.py index 2527f9ef8ca..1efda7233ae 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/industreal_algo_utils.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/industreal_algo_utils.py @@ -105,7 +105,6 @@ def get_sdf_reward( sdf_reward = torch.zeros((num_envs,), dtype=torch.float32, device=device) for i in range(num_envs): - # Create copy of plug mesh mesh_points = wp.clone(wp_plug_mesh.points) mesh_indices = wp.clone(wp_plug_mesh.indices) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py index cee531d58a4..4a6ac5c0122 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py @@ -52,7 +52,6 @@ def compute_softdtw_cuda(D, gamma, bandwidth, max_i, max_j, n_passes, R): # Go over each anti-diagonal. Only process threads that fall on the current on the anti-diagonal for p in range(n_passes): - # The index is actually 'p - tid' but need to force it in-bounds J = max(0, min(p - tid, max_j - 1)) @@ -97,7 +96,6 @@ def compute_softdtw_backward_cuda(D, R, inv_gamma, bandwidth, max_i, max_j, n_pa # Only compute if element[i, j] is on the current anti-diagonal, and also is within bounds if tid + J == rev_p and (tid < max_i and max_j > J): - if math.isinf(R[k, i, j]): R[k, i, j] = -math.inf @@ -199,7 +197,6 @@ def compute_softdtw(D, gamma, bandwidth): for b in prange(B): for j in range(1, M + 1): for i in range(1, N + 1): - # Check the pruning condition if 0 < bandwidth < np.abs(i - j): continue @@ -230,7 +227,6 @@ def compute_softdtw_backward(D_, R, gamma, bandwidth): for k in prange(B): for j in range(M, 0, -1): for i in range(N, 0, -1): - if np.isinf(R[k, i, j]): R[k, i, j] = -np.inf @@ -442,7 +438,6 @@ def profile(batch_size, seq_len_a, seq_len_b, dims, tol_backward): # ---------------------------------------------------------------------------------------------------------------------- if __name__ == "__main__": - torch.manual_seed(1234) profile(128, 17, 15, 2, tol_backward=1e-6) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py index 9284cc7a112..165e14434e4 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py @@ -91,7 +91,6 @@ class CartpoleDepthCameraEnvCfg(CartpoleRGBCameraEnvCfg): class CartpoleCameraEnv(DirectRLEnv): - cfg: CartpoleRGBCameraEnvCfg | CartpoleDepthCameraEnvCfg def __init__( diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env.py index 4fed9a1d8d5..dc03eb299d0 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole_showcase/cartpole/cartpole_env.py @@ -42,7 +42,6 @@ def _apply_action(self) -> None: self.cartpole.set_joint_effort_target(target, joint_ids=self._cart_dof_idx) def _get_observations(self) -> dict: - # fundamental spaces # - Box if isinstance(self.single_observation_space["policy"], gym.spaces.Box): diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/humanoid/agents/rsl_rl_ppo_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/humanoid/agents/rsl_rl_ppo_cfg.py index 5da79221b5b..f2c7f48e455 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/humanoid/agents/rsl_rl_ppo_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/classic/humanoid/agents/rsl_rl_ppo_cfg.py @@ -13,7 +13,6 @@ ==================================================================================================== """ - from isaaclab.utils import configclass from isaaclab_rl.rsl_rl import RslRlOnPolicyRunnerCfg, RslRlPpoActorCriticCfg, RslRlPpoAlgorithmCfg diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/deploy/mdp/events.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/deploy/mdp/events.py index 048e7ca3f76..c8355ccc9d1 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/deploy/mdp/events.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/deploy/mdp/events.py @@ -5,7 +5,6 @@ """Class-based event terms specific to the gear assembly manipulation environments.""" - from __future__ import annotations import random diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/inhand/mdp/events.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/inhand/mdp/events.py index 2b75a1501cc..59dbca4bf97 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/inhand/mdp/events.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/inhand/mdp/events.py @@ -5,7 +5,6 @@ """Functions specific to the in-hand dexterous manipulation environments.""" - from __future__ import annotations import torch diff --git a/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py b/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py index d7aa7674bd4..525b425917f 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py +++ b/source/isaaclab_tasks/isaaclab_tasks/utils/hydra.py @@ -5,7 +5,6 @@ """Sub-module with utilities for the hydra configuration system.""" - import functools from collections.abc import Callable diff --git a/source/isaaclab_tasks/test/test_environments.py b/source/isaaclab_tasks/test/test_environments.py index 2acd2c36652..1b6d17f6aa7 100644 --- a/source/isaaclab_tasks/test/test_environments.py +++ b/source/isaaclab_tasks/test/test_environments.py @@ -28,6 +28,7 @@ # Local imports should be imported last from env_test_utils import _run_environments, setup_environment # isort: skip + @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) @pytest.mark.parametrize("task_name", setup_environment(include_play=False, factory_envs=False, multi_agent=False)) @pytest.mark.isaacsim_ci diff --git a/source/isaaclab_tasks/test/test_factory_environments.py b/source/isaaclab_tasks/test/test_factory_environments.py index 419d7774bbc..05908000655 100644 --- a/source/isaaclab_tasks/test/test_factory_environments.py +++ b/source/isaaclab_tasks/test/test_factory_environments.py @@ -20,6 +20,7 @@ # Local imports should be imported last from env_test_utils import _check_random_actions, setup_environment # isort: skip + @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) @pytest.mark.parametrize("task_name", setup_environment(factory_envs=True, multi_agent=False)) @pytest.mark.isaacsim_ci diff --git a/source/isaaclab_tasks/test/test_lift_teddy_bear.py b/source/isaaclab_tasks/test/test_lift_teddy_bear.py index 99c5fa0fda2..b0d28c93fc5 100644 --- a/source/isaaclab_tasks/test/test_lift_teddy_bear.py +++ b/source/isaaclab_tasks/test/test_lift_teddy_bear.py @@ -29,6 +29,7 @@ # Local imports should be imported last from env_test_utils import _run_environments # isort: skip + @pytest.mark.parametrize("num_envs, device", [(32, "cuda"), (1, "cuda")]) def test_lift_teddy_bear_environment(num_envs, device): """Test the Isaac-Lift-Teddy-Bear-Franka-IK-Abs-v0 environment in isolation.""" diff --git a/source/isaaclab_tasks/test/test_rl_device_separation.py b/source/isaaclab_tasks/test/test_rl_device_separation.py index 38ff159fa77..ef6bd1e093f 100644 --- a/source/isaaclab_tasks/test/test_rl_device_separation.py +++ b/source/isaaclab_tasks/test/test_rl_device_separation.py @@ -96,28 +96,28 @@ def _verify_unwrapped_env(env, sim_device: str): env: Unwrapped gym environment sim_device: Expected simulation device """ - assert ( - env.unwrapped.device == sim_device - ), f"Environment device mismatch: expected {sim_device}, got {env.unwrapped.device}" + assert env.unwrapped.device == sim_device, ( + f"Environment device mismatch: expected {sim_device}, got {env.unwrapped.device}" + ) # Verify reset returns data on sim device obs_dict, _ = env.reset() for key, value in obs_dict.items(): if isinstance(value, torch.Tensor): - assert ( - value.device.type == torch.device(sim_device).type - ), f"Unwrapped env obs '{key}' should be on {sim_device}, got {value.device}" + assert value.device.type == torch.device(sim_device).type, ( + f"Unwrapped env obs '{key}' should be on {sim_device}, got {value.device}" + ) # Verify step returns data on sim device action_space = env.unwrapped.single_action_space test_action = torch.zeros(NUM_ENVS, action_space.shape[0], device=sim_device) obs_dict, rew, term, trunc, extras = env.step(test_action) - assert ( - rew.device.type == torch.device(sim_device).type - ), f"Unwrapped env rewards should be on {sim_device}, got {rew.device}" - assert ( - term.device.type == torch.device(sim_device).type - ), f"Unwrapped env terminated should be on {sim_device}, got {term.device}" + assert rew.device.type == torch.device(sim_device).type, ( + f"Unwrapped env rewards should be on {sim_device}, got {rew.device}" + ) + assert term.device.type == torch.device(sim_device).type, ( + f"Unwrapped env terminated should be on {sim_device}, got {term.device}" + ) def _verify_tensor_device(data, expected_device: str, name: str): @@ -129,15 +129,15 @@ def _verify_tensor_device(data, expected_device: str, name: str): name: Name for error messages """ if isinstance(data, torch.Tensor): - assert ( - data.device.type == torch.device(expected_device).type - ), f"{name} should be on {expected_device}, got {data.device}" + assert data.device.type == torch.device(expected_device).type, ( + f"{name} should be on {expected_device}, got {data.device}" + ) elif isinstance(data, dict): for key, value in data.items(): if isinstance(value, torch.Tensor): - assert ( - value.device.type == torch.device(expected_device).type - ), f"{name}['{key}'] should be on {expected_device}, got {value.device}" + assert value.device.type == torch.device(expected_device).type, ( + f"{name}['{key}'] should be on {expected_device}, got {value.device}" + ) def _test_rsl_rl_device_separation(sim_device: str, rl_device: str): diff --git a/tools/template/cli.py b/tools/template/cli.py index 6150631e555..d922025e070 100644 --- a/tools/template/cli.py +++ b/tools/template/cli.py @@ -73,7 +73,7 @@ def input_checkbox(self, message: str, choices: list[str], default: str | None = def transformer(result: list[str]) -> str: if "all" in result or "both" in result: token = "all" if "all" in result else "both" - return f'{token} ({", ".join(choices[:choices.index("---")])})' + return f"{token} ({', '.join(choices[: choices.index('---')])})" return ", ".join(result) return inquirer.checkbox( diff --git a/tools/template/generator.py b/tools/template/generator.py index 633e4c0f418..da012581d6a 100644 --- a/tools/template/generator.py +++ b/tools/template/generator.py @@ -96,22 +96,22 @@ def _generate_task_per_workflow(task_dir: str, specification: dict) -> None: # workflow-specific content if task_spec["workflow"]["name"] == "direct": # - task/*env_cfg.py - template = jinja_env.get_template(f'tasks/direct_{task_spec["workflow"]["type"]}/env_cfg') + template = jinja_env.get_template(f"tasks/direct_{task_spec['workflow']['type']}/env_cfg") _write_file( - os.path.join(task_dir, f'{task_spec["filename"]}_env_cfg.py'), content=template.render(**specification) + os.path.join(task_dir, f"{task_spec['filename']}_env_cfg.py"), content=template.render(**specification) ) # - task/*env.py - template = jinja_env.get_template(f'tasks/direct_{task_spec["workflow"]["type"]}/env') - _write_file(os.path.join(task_dir, f'{task_spec["filename"]}_env.py'), content=template.render(**specification)) + template = jinja_env.get_template(f"tasks/direct_{task_spec['workflow']['type']}/env") + _write_file(os.path.join(task_dir, f"{task_spec['filename']}_env.py"), content=template.render(**specification)) elif task_spec["workflow"]["name"] == "manager-based": # - task/*env_cfg.py - template = jinja_env.get_template(f'tasks/manager-based_{task_spec["workflow"]["type"]}/env_cfg') + template = jinja_env.get_template(f"tasks/manager-based_{task_spec['workflow']['type']}/env_cfg") _write_file( - os.path.join(task_dir, f'{task_spec["filename"]}_env_cfg.py'), content=template.render(**specification) + os.path.join(task_dir, f"{task_spec['filename']}_env_cfg.py"), content=template.render(**specification) ) # - task/mdp folder shutil.copytree( - os.path.join(TEMPLATE_DIR, "tasks", f'manager-based_{task_spec["workflow"]["type"]}', "mdp"), + os.path.join(TEMPLATE_DIR, "tasks", f"manager-based_{task_spec['workflow']['type']}", "mdp"), os.path.join(task_dir, "mdp"), dirs_exist_ok=True, ) @@ -184,10 +184,12 @@ def _external(specification: dict) -> None: # replace placeholder in scripts for file in glob.glob(os.path.join(dir, rl_library["name"], "*.py")): _replace_in_file( - [( - "# PLACEHOLDER: Extension template (do not remove this comment)", - f"import {name}.tasks # noqa: F401", - )], + [ + ( + "# PLACEHOLDER: Extension template (do not remove this comment)", + f"import {name}.tasks # noqa: F401", + ) + ], src=file, ) # - other scripts @@ -198,10 +200,12 @@ def _external(specification: dict) -> None: ) for script in ["zero_agent.py", "random_agent.py"]: _replace_in_file( - [( - "# PLACEHOLDER: Extension template (do not remove this comment)", - f"import {name}.tasks # noqa: F401", - )], + [ + ( + "# PLACEHOLDER: Extension template (do not remove this comment)", + f"import {name}.tasks # noqa: F401", + ) + ], src=os.path.join(ROOT_DIR, "scripts", "environments", script), dst=os.path.join(dir, script), ) @@ -279,9 +283,9 @@ def get_algorithms_per_rl_library(single_agent: bool = True, multi_agent: bool = basename = os.path.basename(file).replace("_cfg", "") if basename.startswith(f"{rl_library}_"): algorithm = basename.replace(f"{rl_library}_", "").upper() - assert ( - algorithm in SINGLE_AGENT_ALGORITHMS or algorithm in MULTI_AGENT_ALGORITHMS - ), f"{algorithm} algorithm is not listed in the supported algorithms" + assert algorithm in SINGLE_AGENT_ALGORITHMS or algorithm in MULTI_AGENT_ALGORITHMS, ( + f"{algorithm} algorithm is not listed in the supported algorithms" + ) if single_agent and algorithm in SINGLE_AGENT_ALGORITHMS: data[rl_library].append(algorithm) if multi_agent and algorithm in MULTI_AGENT_ALGORITHMS: From 085289f1c89531dc588064f050c55f72dd20a632 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:31:07 +0100 Subject: [PATCH 24/32] keeps black formatting --- .pre-commit-config.yaml | 4 + .../snippets/tutorial_modify_direct_rl_env.py | 1 + pyproject.toml | 187 +++++++++--------- .../ray/grok_cluster_with_kubectl.py | 3 +- .../test_null_space_posture_task.py | 36 ++-- .../isaaclab/test/controllers/test_pink_ik.py | 12 +- .../isaaclab_mimic/datagen/data_generator.py | 24 +-- .../direct/automate/factory_control.py | 4 +- .../direct/automate/soft_dtw_cuda.py | 3 +- .../test/test_rl_device_separation.py | 36 ++-- tools/conftest.py | 14 +- tools/template/generator.py | 26 ++- 12 files changed, 180 insertions(+), 170 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aad10d0ded5..f69eb4c0758 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,6 +12,10 @@ repos: args: ["--fix"] # Run the formatter # - id: ruff-format + - repo: https://github.com/python/black + rev: 24.3.0 + hooks: + - id: black - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: diff --git a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py index 13e150418a3..1436b3fc9a9 100644 --- a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py +++ b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py @@ -7,6 +7,7 @@ # [start-init-import] from .h1_env import H1Env, H1EnvCfg + # [end-init-import] # [start-init-register] diff --git a/pyproject.toml b/pyproject.toml index a2b0e0a188d..5389f3a27a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,102 @@ +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +[tool.black] +line-length = 120 +target-version = ["py311"] +preview = true +unstable = true + +# TODO: Remove this once isort is removed from the project +[tool.isort] + +profile = "black" +py_version = 310 +line_length = 120 +group_by_package = true + +# Files to skip +skip_glob = ["docs/*", "logs/*", "_isaac_sim/*", ".vscode/*"] + +# Order of imports +sections = [ + "FUTURE", + "STDLIB", + "OMNIVERSE_EXTENSIONS", + "THIRDPARTY", + "ASSETS_FIRSTPARTY", + "FIRSTPARTY", + "EXTRA_FIRSTPARTY", + "TASK_FIRSTPARTY", + "LOCALFOLDER", +] + +# Extra standard libraries considered as part of python (permissive licenses +extra_standard_library = [ + "numpy", + "torch", + "einops", + "tensordict", + "warp", + "scipy", + "open3d", + "cv2", + "PIL", + "torchvision", + "transformers", + "h5py", + "yaml", + "toml", + "bpy", + "trimesh", + "matplotlib", + "gymnasium", + "gym", + "hid", + "prettytable", + "tqdm", + "flatdict", + "packaging", + "pytest", + "pytest-mock", + "flaky", +] + +known_third_party = [ + "junitparser", + "pinocchio", + "pink", + "rsl_rl", + "rl_games", + "ray", + "stable_baselines3", + "skrl", + "wandb", + "tensorboard", + "hydra", + "omegaconf", +] + +# Imports from Isaac Sim and Omniverse +known_omniverse_extensions = [ + "carb", + "omni*", + "isaacsim*", + "pxr", + "usdrt", + "Semantics", +] + +# Imports from this repository +known_first_party = "isaaclab" +known_assets_firstparty = "isaaclab_assets" +known_extra_firstparty = ["isaaclab_rl", "isaaclab_mimic"] +known_task_firstparty = "isaaclab_tasks" +# Imports from the local folder +known_local_folder = "config" + [tool.ruff] line-length = 120 target-version = "py310" @@ -95,94 +194,6 @@ section-order = [ "isaaclab-mimic" = ["isaaclab_mimic"] "isaaclab-tasks" = ["isaaclab_tasks"] -# TODO: Remove this once isort is removed from the project -[tool.isort] - -profile = "black" -py_version = 310 -line_length = 120 -group_by_package = true - -# Files to skip -skip_glob = ["docs/*", "logs/*", "_isaac_sim/*", ".vscode/*"] - -# Order of imports -sections = [ - "FUTURE", - "STDLIB", - "OMNIVERSE_EXTENSIONS", - "THIRDPARTY", - "ASSETS_FIRSTPARTY", - "FIRSTPARTY", - "EXTRA_FIRSTPARTY", - "TASK_FIRSTPARTY", - "LOCALFOLDER", -] - -# Extra standard libraries considered as part of python (permissive licenses -extra_standard_library = [ - "numpy", - "torch", - "einops", - "tensordict", - "warp", - "scipy", - "open3d", - "cv2", - "PIL", - "torchvision", - "transformers", - "h5py", - "yaml", - "toml", - "bpy", - "trimesh", - "matplotlib", - "gymnasium", - "gym", - "hid", - "prettytable", - "tqdm", - "flatdict", - "packaging", - "pytest", - "pytest-mock", - "flaky", -] - -known_third_party = [ - "junitparser", - "pinocchio", - "pink", - "rsl_rl", - "rl_games", - "ray", - "stable_baselines3", - "skrl", - "wandb", - "tensorboard", - "hydra", - "omegaconf", -] - -# Imports from Isaac Sim and Omniverse -known_omniverse_extensions = [ - "carb", - "omni*", - "isaacsim*", - "pxr", - "usdrt", - "Semantics", -] - -# Imports from this repository -known_first_party = "isaaclab" -known_assets_firstparty = "isaaclab_assets" -known_extra_firstparty = ["isaaclab_rl", "isaaclab_mimic"] -known_task_firstparty = "isaaclab_tasks" -# Imports from the local folder -known_local_folder = "config" - [tool.ruff.format] # Use Black-compatible formatting quote-style = "double" diff --git a/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py b/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py index bd86d4bd223..0692bd22d49 100644 --- a/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py +++ b/scripts/reinforcement_learning/ray/grok_cluster_with_kubectl.py @@ -30,8 +30,7 @@ def get_namespace() -> str: """Get the current Kubernetes namespace from the context, fallback to default if not set""" try: namespace = ( - subprocess - .check_output(["kubectl", "config", "view", "--minify", "--output", "jsonpath={..namespace}"]) + subprocess.check_output(["kubectl", "config", "view", "--minify", "--output", "jsonpath={..namespace}"]) .decode() .strip() ) diff --git a/source/isaaclab/test/controllers/test_null_space_posture_task.py b/source/isaaclab/test/controllers/test_null_space_posture_task.py index 66db14e9508..cd972c67988 100644 --- a/source/isaaclab/test/controllers/test_null_space_posture_task.py +++ b/source/isaaclab/test/controllers/test_null_space_posture_task.py @@ -151,9 +151,9 @@ def test_null_space_jacobian_properties(self, robot_configuration, tasks, joint_ # Test: N * J^T should be approximately zero (null space property) # where N is the null space projector and J is the end-effector Jacobian null_space_projection = null_space_jacobian @ ee_jacobian.T - assert np.allclose(null_space_projection, np.zeros_like(null_space_projection), atol=1e-7), ( - f"Null space projection of end-effector Jacobian not zero: {null_space_projection}" - ) + assert np.allclose( + null_space_projection, np.zeros_like(null_space_projection), atol=1e-7 + ), f"Null space projection of end-effector Jacobian not zero: {null_space_projection}" def test_null_space_jacobian_identity_when_no_frame_tasks( self, robot_configuration, joint_configurations, num_joints @@ -174,9 +174,9 @@ def test_null_space_jacobian_identity_when_no_frame_tasks( # Should be identity matrix expected_identity = np.eye(num_joints) - assert np.allclose(null_space_jacobian, expected_identity), ( - f"Null space Jacobian should be identity when no frame tasks defined: {null_space_jacobian}" - ) + assert np.allclose( + null_space_jacobian, expected_identity + ), f"Null space Jacobian should be identity when no frame tasks defined: {null_space_jacobian}" def test_null_space_jacobian_consistency_across_configurations( self, robot_configuration, tasks, joint_configurations, num_joints @@ -216,9 +216,9 @@ def test_null_space_jacobian_consistency_across_configurations( null_space_velocity = jacobian @ random_velocity ee_velocity = ee_jacobian @ null_space_velocity - assert np.allclose(ee_velocity, np.zeros(6), atol=1e-7), ( - f"End-effector velocity not zero for configuration {config}: {ee_velocity}" - ) + assert np.allclose( + ee_velocity, np.zeros(6), atol=1e-7 + ), f"End-effector velocity not zero for configuration {config}: {ee_velocity}" def test_compute_error_without_target(self, robot_configuration, joint_configurations): """Test that compute_error raises ValueError when no target is set.""" @@ -264,9 +264,9 @@ def test_joint_masking(self, robot_configuration, joint_configurations, num_join for i in joint_indexes: expected_error[i] = current_config[i] - assert np.allclose(error, expected_error, atol=1e-7), ( - f"Joint mask not working correctly: expected {expected_error}, got {error}" - ) + assert np.allclose( + error, expected_error, atol=1e-7 + ), f"Joint mask not working correctly: expected {expected_error}, got {error}" def test_empty_controlled_joints(self, robot_configuration, joint_configurations, num_joints): """Test behavior when controlled_joints is empty.""" @@ -332,9 +332,9 @@ def test_multiple_frame_tasks(self, robot_configuration, joint_configurations, n ee_velocity_left = jacobian_left_hand @ null_space_velocity ee_velocity_right = jacobian_right_hand @ null_space_velocity - assert np.allclose(ee_velocity_left, np.zeros(6), atol=1e-7), ( - f"Left hand velocity not zero: {ee_velocity_left}" - ) - assert np.allclose(ee_velocity_right, np.zeros(6), atol=1e-7), ( - f"Right hand velocity not zero: {ee_velocity_right}" - ) + assert np.allclose( + ee_velocity_left, np.zeros(6), atol=1e-7 + ), f"Left hand velocity not zero: {ee_velocity_left}" + assert np.allclose( + ee_velocity_right, np.zeros(6), atol=1e-7 + ), f"Right hand velocity not zero: {ee_velocity_right}" diff --git a/source/isaaclab/test/controllers/test_pink_ik.py b/source/isaaclab/test/controllers/test_pink_ik.py index 8d7ee7c6f67..6cf3af6c2e7 100644 --- a/source/isaaclab/test/controllers/test_pink_ik.py +++ b/source/isaaclab/test/controllers/test_pink_ik.py @@ -112,9 +112,9 @@ def env_and_cfg(request): # Try to infer which is left and which is right left_candidates = [f for f in frames if "left" in f.lower()] right_candidates = [f for f in frames if "right" in f.lower()] - assert len(left_candidates) == 1 and len(right_candidates) == 1, ( - f"Could not uniquely identify left/right frames from: {frames}" - ) + assert ( + len(left_candidates) == 1 and len(right_candidates) == 1 + ), f"Could not uniquely identify left/right frames from: {frames}" left_eef_urdf_link_name = left_candidates[0] right_eef_urdf_link_name = right_candidates[0] @@ -367,14 +367,12 @@ def compute_errors( # Calculate PD errors left_pd_error = ( - torch - .tensor(left_target_pos - left_curr_pos, device=device, dtype=torch.float32) + torch.tensor(left_target_pos - left_curr_pos, device=device, dtype=torch.float32) .unsqueeze(0) .repeat(num_envs, 1) ) right_pd_error = ( - torch - .tensor(right_target_pos - right_curr_pos, device=device, dtype=torch.float32) + torch.tensor(right_target_pos - right_curr_pos, device=device, dtype=torch.float32) .unsqueeze(0) .repeat(num_envs, 1) ) diff --git a/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py b/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py index 338b4dc03be..a6f8b3cc017 100644 --- a/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py +++ b/source/isaaclab_mimic/isaaclab_mimic/datagen/data_generator.py @@ -239,9 +239,9 @@ def randomize_subtask_boundaries(self) -> dict[str, np.ndarray]: assert np.all((subtask_boundaries[:, :, 1] - subtask_boundaries[:, :, 0]) > 0), "got empty subtasks!" # Ensure subtask indices increase (both starts and ends) - assert np.all((subtask_boundaries[:, 1:, :] - subtask_boundaries[:, :-1, :]) > 0), ( - "subtask indices do not strictly increase" - ) + assert np.all( + (subtask_boundaries[:, 1:, :] - subtask_boundaries[:, :-1, :]) > 0 + ), "subtask indices do not strictly increase" # Ensure subtasks are in order subtask_inds_flat = subtask_boundaries.reshape(subtask_boundaries.shape[0], -1) @@ -409,17 +409,17 @@ def generate_eef_subtask_trajectory( (concurrent_task_spec_key, concurrent_subtask_ind) ]["transform"] else: - assert "transform" not in runtime_subtask_constraints_dict[(eef_name, subtask_ind)], ( - "transform should not be set for concurrent task" - ) + assert ( + "transform" not in runtime_subtask_constraints_dict[(eef_name, subtask_ind)] + ), "transform should not be set for concurrent task" # Need to transform demo according to scheme coord_transform_scheme = runtime_subtask_constraints_dict[(eef_name, subtask_ind)][ "coordination_scheme" ] if coord_transform_scheme != SubTaskConstraintCoordinationScheme.REPLAY: - assert subtask_object_name is not None, ( - f"object reference should not be None for {coord_transform_scheme} coordination scheme" - ) + assert ( + subtask_object_name is not None + ), f"object reference should not be None for {coord_transform_scheme} coordination scheme" if need_source_demo_selection: selected_src_demo_inds[eef_name] = self.select_source_demo( @@ -445,9 +445,9 @@ def generate_eef_subtask_trajectory( if (eef_name, subtask_ind) in runtime_subtask_constraints_dict: if runtime_subtask_constraints_dict[(eef_name, subtask_ind)]["type"] == SubTaskConstraintType.COORDINATION: # Store selected source demo ind for concurrent task - runtime_subtask_constraints_dict[(eef_name, subtask_ind)]["selected_src_demo_ind"] = ( - selected_src_demo_ind - ) + runtime_subtask_constraints_dict[(eef_name, subtask_ind)][ + "selected_src_demo_ind" + ] = selected_src_demo_ind concurrent_task_spec_key = runtime_subtask_constraints_dict[(eef_name, subtask_ind)][ "concurrent_task_spec_key" ] diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py index 6cd797e7d6d..2bb44200654 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/factory_control.py @@ -117,7 +117,9 @@ def get_pose_error( fingertip_midpoint_quat_norm = torch_utils.quat_mul( fingertip_midpoint_quat, torch_utils.quat_conjugate(fingertip_midpoint_quat) - )[:, 0] # scalar component + )[ + :, 0 + ] # scalar component fingertip_midpoint_quat_inv = torch_utils.quat_conjugate( fingertip_midpoint_quat ) / fingertip_midpoint_quat_norm.unsqueeze(-1) diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py index 4a6ac5c0122..4a197de71c6 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/automate/soft_dtw_cuda.py @@ -399,7 +399,8 @@ def profile(batch_size, seq_len_a, seq_len_b, dims, tol_backward): n_iters = 6 print( - f"Profiling forward() + backward() times for batch_size={batch_size}, seq_len_a={seq_len_a}, seq_len_b={seq_len_b}, dims={dims}..." + f"Profiling forward() + backward() times for batch_size={batch_size}, seq_len_a={seq_len_a}," + f" seq_len_b={seq_len_b}, dims={dims}..." ) times_cpu = [] diff --git a/source/isaaclab_tasks/test/test_rl_device_separation.py b/source/isaaclab_tasks/test/test_rl_device_separation.py index ef6bd1e093f..38ff159fa77 100644 --- a/source/isaaclab_tasks/test/test_rl_device_separation.py +++ b/source/isaaclab_tasks/test/test_rl_device_separation.py @@ -96,28 +96,28 @@ def _verify_unwrapped_env(env, sim_device: str): env: Unwrapped gym environment sim_device: Expected simulation device """ - assert env.unwrapped.device == sim_device, ( - f"Environment device mismatch: expected {sim_device}, got {env.unwrapped.device}" - ) + assert ( + env.unwrapped.device == sim_device + ), f"Environment device mismatch: expected {sim_device}, got {env.unwrapped.device}" # Verify reset returns data on sim device obs_dict, _ = env.reset() for key, value in obs_dict.items(): if isinstance(value, torch.Tensor): - assert value.device.type == torch.device(sim_device).type, ( - f"Unwrapped env obs '{key}' should be on {sim_device}, got {value.device}" - ) + assert ( + value.device.type == torch.device(sim_device).type + ), f"Unwrapped env obs '{key}' should be on {sim_device}, got {value.device}" # Verify step returns data on sim device action_space = env.unwrapped.single_action_space test_action = torch.zeros(NUM_ENVS, action_space.shape[0], device=sim_device) obs_dict, rew, term, trunc, extras = env.step(test_action) - assert rew.device.type == torch.device(sim_device).type, ( - f"Unwrapped env rewards should be on {sim_device}, got {rew.device}" - ) - assert term.device.type == torch.device(sim_device).type, ( - f"Unwrapped env terminated should be on {sim_device}, got {term.device}" - ) + assert ( + rew.device.type == torch.device(sim_device).type + ), f"Unwrapped env rewards should be on {sim_device}, got {rew.device}" + assert ( + term.device.type == torch.device(sim_device).type + ), f"Unwrapped env terminated should be on {sim_device}, got {term.device}" def _verify_tensor_device(data, expected_device: str, name: str): @@ -129,15 +129,15 @@ def _verify_tensor_device(data, expected_device: str, name: str): name: Name for error messages """ if isinstance(data, torch.Tensor): - assert data.device.type == torch.device(expected_device).type, ( - f"{name} should be on {expected_device}, got {data.device}" - ) + assert ( + data.device.type == torch.device(expected_device).type + ), f"{name} should be on {expected_device}, got {data.device}" elif isinstance(data, dict): for key, value in data.items(): if isinstance(value, torch.Tensor): - assert value.device.type == torch.device(expected_device).type, ( - f"{name}['{key}'] should be on {expected_device}, got {value.device}" - ) + assert ( + value.device.type == torch.device(expected_device).type + ), f"{name}['{key}'] should be on {expected_device}, got {value.device}" def _test_rsl_rl_device_separation(sim_device: str, rl_device: str): diff --git a/tools/conftest.py b/tools/conftest.py index e89d2479ab1..bb65825f0de 100644 --- a/tools/conftest.py +++ b/tools/conftest.py @@ -405,14 +405,12 @@ def pytest_sessionstart(session): - test_status[test_path]["errors"] - test_status[test_path]["skipped"] ) - per_test_result_table.add_row( - [ - test_path, - test_status[test_path]["result"], - f"{test_status[test_path]['time_elapsed']:0.2f}", - f"{num_tests_passed}/{test_status[test_path]['tests']}", - ] - ) + per_test_result_table.add_row([ + test_path, + test_status[test_path]["result"], + f"{test_status[test_path]['time_elapsed']:0.2f}", + f"{num_tests_passed}/{test_status[test_path]['tests']}", + ]) summary_str += per_test_result_table.get_string() diff --git a/tools/template/generator.py b/tools/template/generator.py index da012581d6a..493fcf991b6 100644 --- a/tools/template/generator.py +++ b/tools/template/generator.py @@ -184,12 +184,10 @@ def _external(specification: dict) -> None: # replace placeholder in scripts for file in glob.glob(os.path.join(dir, rl_library["name"], "*.py")): _replace_in_file( - [ - ( - "# PLACEHOLDER: Extension template (do not remove this comment)", - f"import {name}.tasks # noqa: F401", - ) - ], + [( + "# PLACEHOLDER: Extension template (do not remove this comment)", + f"import {name}.tasks # noqa: F401", + )], src=file, ) # - other scripts @@ -200,12 +198,10 @@ def _external(specification: dict) -> None: ) for script in ["zero_agent.py", "random_agent.py"]: _replace_in_file( - [ - ( - "# PLACEHOLDER: Extension template (do not remove this comment)", - f"import {name}.tasks # noqa: F401", - ) - ], + [( + "# PLACEHOLDER: Extension template (do not remove this comment)", + f"import {name}.tasks # noqa: F401", + )], src=os.path.join(ROOT_DIR, "scripts", "environments", script), dst=os.path.join(dir, script), ) @@ -283,9 +279,9 @@ def get_algorithms_per_rl_library(single_agent: bool = True, multi_agent: bool = basename = os.path.basename(file).replace("_cfg", "") if basename.startswith(f"{rl_library}_"): algorithm = basename.replace(f"{rl_library}_", "").upper() - assert algorithm in SINGLE_AGENT_ALGORITHMS or algorithm in MULTI_AGENT_ALGORITHMS, ( - f"{algorithm} algorithm is not listed in the supported algorithms" - ) + assert ( + algorithm in SINGLE_AGENT_ALGORITHMS or algorithm in MULTI_AGENT_ALGORITHMS + ), f"{algorithm} algorithm is not listed in the supported algorithms" if single_agent and algorithm in SINGLE_AGENT_ALGORITHMS: data[rl_library].append(algorithm) if multi_agent and algorithm in MULTI_AGENT_ALGORITHMS: From c08193fa9d5b8563a412eb24ff496ca2b129ef6e Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:40:10 +0100 Subject: [PATCH 25/32] fixes doc building --- source/isaaclab/isaaclab/ui/widgets/image_plot.py | 2 ++ .../isaaclab_tasks/direct/cartpole/cartpole_camera_env.py | 1 + .../isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py | 2 ++ .../isaaclab_tasks/direct/humanoid_amp/motions/motion_viewer.py | 1 + 4 files changed, 6 insertions(+) diff --git a/source/isaaclab/isaaclab/ui/widgets/image_plot.py b/source/isaaclab/isaaclab/ui/widgets/image_plot.py index 8ca25144135..6afecca55dd 100644 --- a/source/isaaclab/isaaclab/ui/widgets/image_plot.py +++ b/source/isaaclab/isaaclab/ui/widgets/image_plot.py @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations + import logging import numpy as np from contextlib import suppress diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py index 165e14434e4..9284cc7a112 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_env.py @@ -91,6 +91,7 @@ class CartpoleDepthCameraEnvCfg(CartpoleRGBCameraEnvCfg): class CartpoleCameraEnv(DirectRLEnv): + cfg: CartpoleRGBCameraEnvCfg | CartpoleDepthCameraEnvCfg def __init__( diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py b/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py index d81ae0d245c..756f6c61604 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_loader.py @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations + import numpy as np import os import torch diff --git a/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_viewer.py b/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_viewer.py index e9981a94823..55125715b4b 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_viewer.py +++ b/source/isaaclab_tasks/isaaclab_tasks/direct/humanoid_amp/motions/motion_viewer.py @@ -2,6 +2,7 @@ # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause + from __future__ import annotations import matplotlib From 7f7482c178741dcba813ceb7e8330c12be7064f4 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:44:36 +0100 Subject: [PATCH 26/32] fixes docs for ruff --- .vscode/tools/settings.template.json | 5 ++--- docs/source/overview/developer-guide/vs_code.rst | 7 +++---- docs/source/refs/contributing.rst | 3 +-- .../external/.vscode/tools/settings.template.json | 7 +++---- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.vscode/tools/settings.template.json b/.vscode/tools/settings.template.json index f511f3fddb4..c238bc4a85b 100644 --- a/.vscode/tools/settings.template.json +++ b/.vscode/tools/settings.template.json @@ -63,9 +63,8 @@ "python.languageServer": "Pylance", // We use "black" as a formatter: "black-formatter.args": ["--line-length", "120", "--unstable"], - // Use flake8 for linting - "flake8.enabled": true, - "flake8.args": ["--config", "${workspaceFolder}/pyproject.toml"], + // Use ruff as a linter + "ruff.configuration": "${workspaceFolder}/pyproject.toml", // Use docstring generator "autoDocstring.docstringFormat": "google", "autoDocstring.guessTypes": true, diff --git a/docs/source/overview/developer-guide/vs_code.rst b/docs/source/overview/developer-guide/vs_code.rst index 5464e1e7a64..b66479042fe 100644 --- a/docs/source/overview/developer-guide/vs_code.rst +++ b/docs/source/overview/developer-guide/vs_code.rst @@ -80,15 +80,14 @@ refer to the `VSCode documentation `_ as a formatter and `flake8 `_ as a linter. These are configured in the ``.vscode/settings.json`` file: +We use `black `_ as a formatter and `ruff `_ as a linter. These are configured in the ``.vscode/settings.json`` file: .. code-block:: json { "black-formatter.args": ["--line-length", "120", "--unstable"], - "flake8.enabled": true, - "flake8.args": ["--config", "${workspaceFolder}/pyproject.toml"], + "ruff.configuration": "${workspaceFolder}/pyproject.toml", } The black formatter will automatically format your code to match the project's style guide (120 character line length). -The flake8 linter will show warnings and errors in your code to help you follow Python best practices and the project's coding standards. +The ruff linter will show warnings and errors in your code to help you follow Python best practices and the project's coding standards. diff --git a/docs/source/refs/contributing.rst b/docs/source/refs/contributing.rst index bc2d60c426a..7653a001dd7 100644 --- a/docs/source/refs/contributing.rst +++ b/docs/source/refs/contributing.rst @@ -516,8 +516,7 @@ We use the following tools for maintaining code quality: * `pre-commit `__: Runs a list of formatters and linters over the codebase. * `black `__: The uncompromising code formatter. -* `flake8 `__: A wrapper around PyFlakes, pycodestyle and - McCabe complexity checker. +* `ruff `__: An extremely fast Python linter and formatter. Please check `here `__ for instructions to set these up. To run over the entire repository, please execute the diff --git a/tools/template/templates/external/.vscode/tools/settings.template.json b/tools/template/templates/external/.vscode/tools/settings.template.json index 99dc714bb2c..716897355e6 100644 --- a/tools/template/templates/external/.vscode/tools/settings.template.json +++ b/tools/template/templates/external/.vscode/tools/settings.template.json @@ -56,10 +56,9 @@ // This enables python language server. Seems to work slightly better than jedi: "python.languageServer": "Pylance", // We use "black" as a formatter: - "black-formatter.args": ["--line-length", "120"], - // Use flake8 for linting - "flake8.enabled": true, - "flake8.args": ["--config", "${workspaceFolder}/pyproject.toml"], + "black-formatter.args": ["--line-length", "120", "--unstable"], + // Use ruff as a linter + "ruff.configuration": "${workspaceFolder}/pyproject.toml", // Use docstring generator "autoDocstring.docstringFormat": "google", "autoDocstring.guessTypes": true, From ede37e1dad16a4bb9eaedf1ecde0cef6cec29b07 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:50:16 +0100 Subject: [PATCH 27/32] undos unintended enters --- docs/source/refs/snippets/tutorial_modify_direct_rl_env.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py index 1436b3fc9a9..174970bd18e 100644 --- a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py +++ b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py @@ -7,7 +7,6 @@ # [start-init-import] from .h1_env import H1Env, H1EnvCfg - # [end-init-import] # [start-init-register] @@ -26,7 +25,6 @@ # [start-h1_env-import] from isaaclab_assets import H1_CFG - # [end-h1_env-import] # [start-h1_env-spaces] From 0c7d8cfd647e0c1fa94aa623dd95e6ac10df7d0f Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:51:20 +0100 Subject: [PATCH 28/32] adds ruff license --- docs/licenses/dependencies/ruff-license.txt | 430 ++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 docs/licenses/dependencies/ruff-license.txt diff --git a/docs/licenses/dependencies/ruff-license.txt b/docs/licenses/dependencies/ruff-license.txt new file mode 100644 index 00000000000..655a0c76fc5 --- /dev/null +++ b/docs/licenses/dependencies/ruff-license.txt @@ -0,0 +1,430 @@ +MIT License + +Copyright (c) 2022 Charles Marsh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +end of terms and conditions + +The externally maintained libraries from which parts of the Software is derived +are: + +- autoflake, licensed as follows: + """ + Copyright (C) 2012-2018 Steven Myint + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- autotyping, licensed as follows: + """ + MIT License + + Copyright (c) 2023 Jelle Zijlstra + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- Flake8, licensed as follows: + """ + == Flake8 License (MIT) == + + Copyright (C) 2011-2013 Tarek Ziade + Copyright (C) 2012-2016 Ian Cordasco + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- flake8-eradicate, licensed as follows: + """ + MIT License + + Copyright (c) 2018 Nikita Sobolev + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- flake8-pyi, licensed as follows: + """ + The MIT License (MIT) + + Copyright (c) 2016 Łukasz Langa + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- flake8-simplify, licensed as follows: + """ + MIT License + + Copyright (c) 2020 Martin Thoma + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- isort, licensed as follows: + """ + The MIT License (MIT) + + Copyright (c) 2013 Timothy Edmund Crosley + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- pygrep-hooks, licensed as follows: + """ + Copyright (c) 2018 Anthony Sottile + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- pycodestyle, licensed as follows: + """ + Copyright © 2006-2009 Johann C. Rocholl + Copyright © 2009-2014 Florent Xicluna + Copyright © 2014-2020 Ian Lee + + Licensed under the terms of the Expat License + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- pydocstyle, licensed as follows: + """ + Copyright (c) 2012 GreenSteam, + + Copyright (c) 2014-2020 Amir Rachum, + + Copyright (c) 2020 Sambhav Kothari, + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- Pyflakes, licensed as follows: + """ + Copyright 2005-2011 Divmod, Inc. + Copyright 2013-2014 Florent Xicluna + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- Pyright, licensed as follows: + """ + MIT License + + Pyright - A static type checker for the Python language + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + """ + +- pyupgrade, licensed as follows: + """ + Copyright (c) 2017 Anthony Sottile + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- rome/tools, licensed under the MIT license: + """ + MIT License + + Copyright (c) Rome Tools, Inc. and its affiliates. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- RustPython, licensed as follows: + """ + MIT License + + Copyright (c) 2020 RustPython Team + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- rust-analyzer/text-size, licensed under the MIT license: + """ + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + """ From b7dfb0872d516442777d7ec3affc1bf875a1f40c Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:52:00 +0100 Subject: [PATCH 29/32] adds ruff pre commit license --- .../dependencies/ruff-pre-commit-license.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs/licenses/dependencies/ruff-pre-commit-license.txt diff --git a/docs/licenses/dependencies/ruff-pre-commit-license.txt b/docs/licenses/dependencies/ruff-pre-commit-license.txt new file mode 100644 index 00000000000..c16d8bb1db2 --- /dev/null +++ b/docs/licenses/dependencies/ruff-pre-commit-license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Astral Software Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From fad4bd661333629cc1b2cdf5e21c0250f8fd86aa Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:55:48 +0100 Subject: [PATCH 30/32] fixes bug --- source/isaaclab_tasks/isaaclab_tasks/utils/importer.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py b/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py index 7e284520913..ddbab7ede41 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py +++ b/source/isaaclab_tasks/isaaclab_tasks/utils/importer.py @@ -60,10 +60,11 @@ def _walk_packages( ``pkgutil.walk_packages`` function for more details. """ + # Default blacklist if blacklist_pkgs is None: blacklist_pkgs = [] - def seen(p: str, m: dict[str, bool]) -> bool: + def seen(p: str, m: dict[str, bool] = {}) -> bool: """Check if a package has been seen before.""" if p in m: return True @@ -87,11 +88,9 @@ def seen(p: str, m: dict[str, bool]) -> bool: else: raise else: - path = getattr(sys.modules[info.name], "__path__", None) or None + path: list = getattr(sys.modules[info.name], "__path__", []) - # create dictionary to store seen packages - m = {} # don't traverse path items we've seen before - path = [p for p in path if not seen(p, m)] + path = [p for p in path if not seen(p)] yield from _walk_packages(path, info.name + ".", onerror, blacklist_pkgs) From 44372536d3ea51a8e6eb632b32fa30a6bce38b7e Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 13:57:16 +0100 Subject: [PATCH 31/32] disables formatting --- docs/source/refs/snippets/tutorial_modify_direct_rl_env.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py index 174970bd18e..e839abf2009 100644 --- a/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py +++ b/docs/source/refs/snippets/tutorial_modify_direct_rl_env.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: BSD-3-Clause # ruff: noqa +# fmt: off # [start-init-import] from .h1_env import H1Env, H1EnvCfg From 9b22204471f98c5b12382c3e357fbb34af798694 Mon Sep 17 00:00:00 2001 From: Mayank Mittal Date: Tue, 13 Jan 2026 14:03:43 +0100 Subject: [PATCH 32/32] uses official link --- docs/source/overview/developer-guide/vs_code.rst | 2 +- docs/source/refs/contributing.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/overview/developer-guide/vs_code.rst b/docs/source/overview/developer-guide/vs_code.rst index b66479042fe..cc883131cfe 100644 --- a/docs/source/overview/developer-guide/vs_code.rst +++ b/docs/source/overview/developer-guide/vs_code.rst @@ -80,7 +80,7 @@ refer to the `VSCode documentation `_ as a formatter and `ruff `_ as a linter. These are configured in the ``.vscode/settings.json`` file: +We use `black `_ as a formatter and `ruff `_ as a linter. These are configured in the ``.vscode/settings.json`` file: .. code-block:: json diff --git a/docs/source/refs/contributing.rst b/docs/source/refs/contributing.rst index 7653a001dd7..3b0f534b71e 100644 --- a/docs/source/refs/contributing.rst +++ b/docs/source/refs/contributing.rst @@ -516,7 +516,7 @@ We use the following tools for maintaining code quality: * `pre-commit `__: Runs a list of formatters and linters over the codebase. * `black `__: The uncompromising code formatter. -* `ruff `__: An extremely fast Python linter and formatter. +* `ruff `__: An extremely fast Python linter and formatter. Please check `here `__ for instructions to set these up. To run over the entire repository, please execute the