diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b4f0b50306ef..5f6ac0491f34 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,11 +2,8 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "ms-vscode.cpptools", "ms-python.python", - "ms-python.vscode-pylance", - "ban.spellright", - "ms-iot.vscode-ros", - "ExecutableBookProject.myst-highlight", + "ms-python.vscode-pylance", + "charliermarsh.ruff", ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 19da23a46ed0..d954d6342129 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -18,12 +18,7 @@ // run formatter "label": "run_formatter", "type": "shell", - "linux": { - "command": "${workspaceFolder}/isaaclab.sh --format" - }, - "windows": { - "command": "${workspaceFolder}/isaaclab.bat --format" - } + "command": "uv run isaaclab --format" } ] } diff --git a/.vscode/tools/launch.template.json b/.vscode/tools/launch.template.json index 3f6536429d93..1d56f46f1c83 100644 --- a/.vscode/tools/launch.template.json +++ b/.vscode/tools/launch.template.json @@ -6,8 +6,10 @@ "configurations": [ { "name": "Python: Current File", - "type": "python", + "type": "debugpy", "request": "launch", + // Use the interpreter recorded by `isaaclab --editor`; VS Code skips wrapper scripts such as python.sh + "python": "${config:python.defaultInterpreterPath}", "program": "${file}", "console": "integratedTerminal" }, @@ -15,35 +17,40 @@ // Usage (VSCode but should be similar for other IDEs): // 1. Set your breakpoints // 2. Run your code under debugpy like so: - // ./isaaclab.sh -p -m debugpy --listen 3000 --wait-for-client -c "from isaaclab.cli import cli; cli()" [cli_args] + // uv run python -m debugpy --listen 3000 --wait-for-client -c "from isaaclab.cli import cli; cli()" [cli_args] // 3. Select this "Python: Debugger Attach" configuration and press green play button or F5 { "name": "Python: Debugger Attach", - "type": "python", + "type": "debugpy", "request": "attach", - "port": 3000, - "host": "localhost" + "connect": { + "host": "localhost", + "port": 3000 + } }, { "name": "Python: Train Environment", - "type": "python", + "type": "debugpy", "request": "launch", - "args" : ["--task", "Isaac-Reach-Franka-v0"], - "program": "${workspaceFolder}/scripts/reinforcement_learning/rsl_rl/train.py", + "python": "${config:python.defaultInterpreterPath}", + "module": "isaaclab", + "args": ["train", "--rl_library", "rsl_rl", "--task", "Isaac-Reach-Franka"], "console": "integratedTerminal" }, { "name": "Python: Play Environment", - "type": "python", + "type": "debugpy", "request": "launch", - "args" : ["--task", "Isaac-Reach-Franka-v0", "--num_envs", "32"], - "program": "${workspaceFolder}/scripts/reinforcement_learning/rsl_rl/play.py", + "python": "${config:python.defaultInterpreterPath}", + "module": "isaaclab", + "args": ["play", "--rl_library", "rsl_rl", "--task", "Isaac-Reach-Franka", "--num_envs", "32"], "console": "integratedTerminal" }, { "name": "Python: SinglePytest", - "type": "python", + "type": "debugpy", "request": "launch", + "python": "${config:python.defaultInterpreterPath}", "module": "pytest", "args": [ "${file}" @@ -52,8 +59,9 @@ }, { "name": "Python: ALL Pytest", - "type": "python", + "type": "debugpy", "request": "launch", + "python": "${config:python.defaultInterpreterPath}", "module": "pytest", "args": ["source/isaaclab/test"], "console": "integratedTerminal", diff --git a/.vscode/tools/settings.template.json b/.vscode/tools/settings.template.json index e9ade2972128..1f578cf97c8f 100644 --- a/.vscode/tools/settings.template.json +++ b/.vscode/tools/settings.template.json @@ -5,7 +5,6 @@ "**/*.egg-info": true }, "files.associations": { - "*.tpp": "cpp", "*.kit": "toml", "*.rst": "restructuredtext" }, @@ -19,59 +18,14 @@ "**/_isaac_sim/**": true, "**/_compiler/**": true }, - // Configuration for spelling checker - "spellright.language": [ - "en-US-10-1." - ], - "spellright.documentTypes": [ - "markdown", - "latex", - "plaintext", - "cpp", - "asciidoc", - "python", - "restructuredtext" - ], - "cSpell.words": [ - "literalinclude", - "linenos", - "instanceable", - "isaacSim", - "jacobians", - "pointcloud", - "ridgeback", - "rllib", - "robomimic", - "teleoperation", - "xform", - "numpy", - "flatcache", - "physx", - "dpad", - "gamepad", - "linspace", - "upsampled", - "downsampled", - "arange", - "discretization", - "trimesh", - "uninstanceable", - "coeff", - "prestartup" - ], // This enables python language server. Seems to work slightly better than jedi: "python.languageServer": "Pylance", // Use ruff as a formatter and linter "ruff.configuration": "${workspaceFolder}/pyproject.toml", - // Use docstring generator - "autoDocstring.docstringFormat": "google", - "autoDocstring.guessTypes": true, // Python environment path // note: the default interpreter is overridden when user selects a workspace interpreter // in the status bar. For example, the virtual environment python interpreter "python.defaultInterpreterPath": "${workspaceFolder}/_isaac_sim/python.sh", - // ROS distribution - "ros.distro": "noetic", // Language specific settings "[python]": { "editor.tabSize": 4 diff --git a/docs/source/developer-tools/editor_setup.rst b/docs/source/developer-tools/editor_setup.rst index 05d54a151342..c66d4c37379b 100644 --- a/docs/source/developer-tools/editor_setup.rst +++ b/docs/source/developer-tools/editor_setup.rst @@ -184,6 +184,13 @@ The editor selection takes precedence over this default. If you change environments, rerun setup and select the new interpreter from the status bar or with **Python: Select Interpreter** in the command palette. +The generated launch configurations always run this recorded interpreter. VS Code +resolves wrapper scripts such as ``_isaac_sim/python.sh`` to the underlying Python +executable, which skips the environment setup that Isaac Sim requires. If +``.vscode/launch.json`` already exists, setup preserves it; add +``"python": "${config:python.defaultInterpreterPath}"`` to each configuration, or +delete the file and rerun setup to regenerate it. + For more information about selecting a Python interpreter, see the `VS Code documentation `_. diff --git a/source/isaaclab/changelog.d/cleanup-vscode-recommendations.rst b/source/isaaclab/changelog.d/cleanup-vscode-recommendations.rst new file mode 100644 index 000000000000..b413454532ff --- /dev/null +++ b/source/isaaclab/changelog.d/cleanup-vscode-recommendations.rst @@ -0,0 +1,7 @@ +Fixed +^^^^^ + +* Fixed ``isaaclab --editor`` failing or writing invalid JSON when the interpreter path contained + backslashes. The interpreter path in ``.vscode/settings.json`` was JSON-encoded. +* Removed the deprecated Black, Flake8, and Jedi settings from the fallback VS Code settings + generated by ``isaaclab --editor`` in favor of Ruff. diff --git a/source/isaaclab/isaaclab/utils/editor.py b/source/isaaclab/isaaclab/utils/editor.py index cd60f651a374..7b3625d6882e 100644 --- a/source/isaaclab/isaaclab/utils/editor.py +++ b/source/isaaclab/isaaclab/utils/editor.py @@ -19,15 +19,8 @@ "editor.rulers": [120], "python.languageServer": "Pylance", - "python.jediEnabled": false, "python.defaultInterpreterPath": "", - "python.formatting.provider": "black", - "python.formatting.blackArgs": ["--line-length", "120"], - - "python.linting.pylintEnabled": false, - "python.linting.flake8Enabled": true, - "[python]": { "editor.tabSize": 4 } @@ -227,9 +220,11 @@ def _overwrite_default_python_interpreter(settings: str, isaacsim_dir: pathlib.P wrapper = isaacsim_dir / "python.sh" if wrapper.is_file(): python_exe = wrapper + # JSON-encode the path and bypass re.sub escape handling so backslashes stay valid + interpreter_setting = f'"python.defaultInterpreterPath": {json.dumps(python_exe.as_posix())}' return re.sub( r'"python\.defaultInterpreterPath": ".*?"', - f'"python.defaultInterpreterPath": "{python_exe.as_posix()}"', + lambda _: interpreter_setting, settings, flags=re.DOTALL, ) diff --git a/source/isaaclab_rl/changelog.d/cleanup-vscode-recommendations.skip b/source/isaaclab_rl/changelog.d/cleanup-vscode-recommendations.skip new file mode 100644 index 000000000000..447383f1447f --- /dev/null +++ b/source/isaaclab_rl/changelog.d/cleanup-vscode-recommendations.skip @@ -0,0 +1 @@ +Extended editor setup test coverage to interpreter paths containing backslashes. No user-visible behavior changed. diff --git a/source/isaaclab_rl/test/test_template_generator.py b/source/isaaclab_rl/test/test_template_generator.py index be78243018cc..cb1b9017dff5 100644 --- a/source/isaaclab_rl/test/test_template_generator.py +++ b/source/isaaclab_rl/test/test_template_generator.py @@ -483,8 +483,10 @@ def test_editor_setup_combines_simulator_local_and_installed_paths(tmp_path, mon ] -def test_editor_setup_uses_workspace_templates(tmp_path, monkeypatch): - """Editor setup must generate workspace files without a project-local Python wrapper.""" +@pytest.mark.parametrize("interpreter", [sys.executable, r"C:\Users\me\.venv\Scripts\python.exe"]) +def test_editor_setup_uses_workspace_templates(tmp_path, monkeypatch, interpreter): + """Editor setup must generate valid workspace files without a project-local Python wrapper.""" + monkeypatch.setattr(sys, "executable", interpreter) project_dir = tmp_path / "project" tools_dir = project_dir / ".vscode" / "tools" tools_dir.mkdir(parents=True) @@ -499,7 +501,8 @@ def test_editor_setup_uses_workspace_templates(tmp_path, monkeypatch): settings = (project_dir / ".vscode" / "settings.json").read_text() assert "automatically generated by `isaaclab --editor`" in settings - assert Path(sys.executable).as_posix() in settings + settings_json = json.loads("".join(line for line in settings.splitlines() if not line.startswith("//"))) + assert settings_json["python.defaultInterpreterPath"] == Path(interpreter).as_posix() assert (project_dir / ".vscode" / "launch.json").is_file() assert not (tools_dir / "setup_vscode.py").exists() assert json.loads((project_dir / "pyrightconfig.json").read_text()) == {"extraPaths": []} diff --git a/tools/template/templates/external/.vscode/extensions.json b/tools/template/templates/external/.vscode/extensions.json index 6306e4349708..5f6ac0491f34 100644 --- a/tools/template/templates/external/.vscode/extensions.json +++ b/tools/template/templates/external/.vscode/extensions.json @@ -4,9 +4,6 @@ "recommendations": [ "ms-python.python", "ms-python.vscode-pylance", - "ban.spellright", - "ms-iot.vscode-ros", - "ms-python.black-formatter", - "ms-python.flake8", + "charliermarsh.ruff", ] } diff --git a/tools/template/templates/external/.vscode/tools/launch.template.json b/tools/template/templates/external/.vscode/tools/launch.template.json index 4be125c68438..9f3529015494 100644 --- a/tools/template/templates/external/.vscode/tools/launch.template.json +++ b/tools/template/templates/external/.vscode/tools/launch.template.json @@ -5,6 +5,8 @@ "name": "Python: Current File", "type": "debugpy", "request": "launch", + // Use the interpreter recorded by `isaaclab --editor`; VS Code skips wrapper scripts such as python.sh + "python": "${config:python.defaultInterpreterPath}", "program": "${file}", "console": "integratedTerminal" }, @@ -15,6 +17,7 @@ "name": "Train {{ specification.task.id }} with {{ rl_library.name }} ({{ rl_algorithm|upper }})", "type": "debugpy", "request": "launch", + "python": "${config:python.defaultInterpreterPath}", "module": "isaaclab", "args": [ "train", @@ -29,6 +32,7 @@ "name": "Play {{ specification.task.id }} with {{ rl_library.name }} ({{ rl_algorithm|upper }})", "type": "debugpy", "request": "launch", + "python": "${config:python.defaultInterpreterPath}", "module": "isaaclab", "args": [ "play", diff --git a/tools/template/templates/external/.vscode/tools/settings.template.json b/tools/template/templates/external/.vscode/tools/settings.template.json index d66c6f4f0322..e19e41385796 100644 --- a/tools/template/templates/external/.vscode/tools/settings.template.json +++ b/tools/template/templates/external/.vscode/tools/settings.template.json @@ -1,6 +1,5 @@ { "files.associations": { - "*.tpp": "cpp", "*.kit": "toml", "*.rst": "restructuredtext" }, @@ -14,58 +13,14 @@ "**/_isaac_sim/**": true, "**/_compiler/**": true }, - // Configuration for spelling checker - "spellright.language": [ - "en-US-10-1." - ], - "spellright.documentTypes": [ - "markdown", - "latex", - "plaintext", - "cpp", - "asciidoc", - "python", - "restructuredtext" - ], - "cSpell.words": [ - "literalinclude", - "linenos", - "instanceable", - "isaacSim", - "jacobians", - "pointcloud", - "ridgeback", - "rllib", - "robomimic", - "teleoperation", - "xform", - "numpy", - "tensordict", - "flatcache", - "physx", - "dpad", - "gamepad", - "linspace", - "upsampled", - "downsampled", - "arange", - "discretization", - "trimesh", - "uninstanceable" - ], // This enables python language server. Seems to work slightly better than jedi: "python.languageServer": "Pylance", // Use ruff as a formatter and linter "ruff.configuration": "${workspaceFolder}/pyproject.toml", - // Use docstring generator - "autoDocstring.docstringFormat": "google", - "autoDocstring.guessTypes": true, // Python environment path // note: the default interpreter is overridden when user selects a workspace interpreter // in the status bar. For example, the virtual environment python interpreter "python.defaultInterpreterPath": "", - // ROS distribution - "ros.distro": "noetic", // Language specific settings "[python]": { "editor.tabSize": 4