From d6ba4276d648beffc3dc268f60c3e7251b3f767c Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Mon, 20 Jul 2026 22:56:59 -0700 Subject: [PATCH 1/5] Fix extraPaths --- .../overview/developer-guide/vs_code.rst | 16 ++ pyproject.toml | 21 ++ tools/template/generator.py | 4 + .../.vscode/tools/settings.template.json | 10 +- .../external/.vscode/tools/setup_vscode.py | 187 ++++++++++-------- tools/template/templates/external/README.md | 24 ++- 6 files changed, 169 insertions(+), 93 deletions(-) diff --git a/docs/source/overview/developer-guide/vs_code.rst b/docs/source/overview/developer-guide/vs_code.rst index 11946a71c769..9325d7e6f3c4 100644 --- a/docs/source/overview/developer-guide/vs_code.rst +++ b/docs/source/overview/developer-guide/vs_code.rst @@ -49,6 +49,22 @@ If everything executes correctly, it should create the following files: * ``.vscode/launch.json``: Contains the launch configurations for debugging python code. * ``.vscode/settings.json``: Contains the settings for the python interpreter and the python environment. +.. note:: + + Type information for the Isaac Lab packages (``isaaclab``, ``isaaclab_tasks``, ...) works out of + the box without running this task: the in-repo source roots are registered via + ``extraPaths`` in the ``[tool.pyright]`` table of the root ``pyproject.toml``, which is read by + both Pylance (VS Code) and basedpyright (Cursor). Running ``setup_python_env`` is only needed to + select the Isaac Sim python interpreter and to index the Isaac Sim extensions (``omni.*``, + ``pxr.*``, ``isaacsim.*``). + +.. note:: + + **Using Cursor?** Cursor cannot run Pylance (it is licensed for official VS Code builds only), so + install the `basedpyright `__ + extension (``detachhead.basedpyright``) as the language server. It reads the same ``[tool.pyright]`` + configuration, so Isaac Lab type information works there without any extra setup. + For more information on VSCode support for Omniverse, please refer to the following links: diff --git a/pyproject.toml b/pyproject.toml index c2f373ca89a6..4e9a6f6d7606 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -273,6 +273,27 @@ exclude = [ ".vscode", ] +# Make the in-repo packages resolvable by the language server (Pylance / basedpyright) +# without an editable install, so imports like ``isaaclab.assets`` work out of the box. +# These are machine-independent relative paths. Add new source packages here when created. +extraPaths = [ + "source/isaaclab", + "source/isaaclab_assets", + "source/isaaclab_contrib", + "source/isaaclab_experimental", + "source/isaaclab_mimic", + "source/isaaclab_newton", + "source/isaaclab_ov", + "source/isaaclab_ovphysx", + "source/isaaclab_physx", + "source/isaaclab_ppisp", + "source/isaaclab_rl", + "source/isaaclab_tasks", + "source/isaaclab_tasks_experimental", + "source/isaaclab_teleop", + "source/isaaclab_visualizers", +] + typeCheckingMode = "basic" pythonVersion = "3.12" pythonPlatform = "Linux" diff --git a/tools/template/generator.py b/tools/template/generator.py index 2460f23992ef..23ad09dc958e 100644 --- a/tools/template/generator.py +++ b/tools/template/generator.py @@ -178,6 +178,10 @@ def _external(specification: dict) -> None: shutil.copyfile(os.path.join(ROOT_DIR, ".gitattributes"), os.path.join(project_dir, ".gitattributes")) if os.path.exists(os.path.join(ROOT_DIR, ".gitignore")): shutil.copyfile(os.path.join(ROOT_DIR, ".gitignore"), os.path.join(project_dir, ".gitignore")) + # the pyrightconfig.json generated by the setup_python_env task holds machine-specific + # Isaac Sim paths, so keep it out of version control + with open(os.path.join(project_dir, ".gitignore"), "a") as f: + f.write("\n# VS Code / Cursor Pyright config generated by .vscode/tools/setup_vscode.py\npyrightconfig.json\n") shutil.copyfile( os.path.join(ROOT_DIR, ".pre-commit-config.yaml"), os.path.join(project_dir, ".pre-commit-config.yaml") ) diff --git a/tools/template/templates/external/.vscode/tools/settings.template.json b/tools/template/templates/external/.vscode/tools/settings.template.json index c1528d65dd73..94dc8dfebe71 100644 --- a/tools/template/templates/external/.vscode/tools/settings.template.json +++ b/tools/template/templates/external/.vscode/tools/settings.template.json @@ -72,8 +72,10 @@ }, "[restructuredtext]": { "editor.tabSize": 2 - }, - // Python extra paths - // Note: this is filled up when vscode is set up for the first time - "python.analysis.extraPaths": [] + } + // Note: python.analysis.extraPaths is intentionally not set here. + // The setup_python_env task writes the Isaac Sim kit-extension and + // source/ search paths to pyrightconfig.json instead, which + // works in both VS Code (Pylance) and Cursor (basedpyright) and does + // not conflict with the [tool.pyright] table in pyproject.toml. } diff --git a/tools/template/templates/external/.vscode/tools/setup_vscode.py b/tools/template/templates/external/.vscode/tools/setup_vscode.py index 8d29dafee080..e4c5b5cd557c 100644 --- a/tools/template/templates/external/.vscode/tools/setup_vscode.py +++ b/tools/template/templates/external/.vscode/tools/setup_vscode.py @@ -3,113 +3,132 @@ # # SPDX-License-Identifier: BSD-3-Clause -"""This script sets up the vs-code settings for the Isaac Lab project. +"""This script sets up the VS Code / Cursor settings for a generated Isaac Lab project. -This script merges the python.analysis.extraPaths from the "{ISAACSIM_DIR}/.vscode/settings.json" file into -the ".vscode/settings.json" file. +It generates a ``pyrightconfig.json`` at the project root that adds the Isaac Sim +kit-extension search paths (for ``omni.*``, ``pxr.*``, ``isaacsim.*`` type information) and +the project's own ``source/`` packages to the language server's search paths. -This is necessary because Isaac Sim 2022.2.1 onwards does not add the necessary python packages to the python path -when the "setup_python_env.sh" is run as part of the vs-code launch configuration. +These paths are written to ``pyrightconfig.json`` instead of ``python.analysis.extraPaths`` +in ``settings.json`` on purpose: ``pyrightconfig.json`` is read by Pylance (VS Code) and +basedpyright (Cursor) alike, and it does not conflict with a ``[tool.pyright]`` table in +``pyproject.toml`` (which makes VS Code reject ``python.analysis.extraPaths``). + +Running this script is optional. For most task authoring it is enough to select the Python +interpreter that has Isaac Lab installed and to run ``pip install -e source/`` - +that already resolves ``isaaclab.*`` and the project's own package. Run this script when you +also want static type information for the Isaac Sim kit extensions. """ +import argparse +import json +import os +import pathlib import re import subprocess import sys -import os -import pathlib ISAACLAB_DIR = pathlib.Path(__file__).parents[2] -"""Path to the Isaac Lab directory.""" - -# Try to find IsaacSim dir -_isaacsim_probe = subprocess.run( - [sys.executable, "-c", "import isaacsim; import os; print(os.environ.get('ISAAC_PATH', ''))"], - capture_output=True, - text=True, - check=False, - # avoid EULA prompt - stdin=subprocess.DEVNULL, -) -if _isaacsim_probe.returncode == 0 and _isaacsim_probe.stdout.strip(): - isaacsim_dir = _isaacsim_probe.stdout.strip() -else: - isaacsim_dir = os.path.join(ISAACLAB_DIR, "_isaac_sim") - -# check if the isaac-sim directory exists -if not os.path.exists(isaacsim_dir): - print( - f"[WARN] Could not find the isaac-sim directory: {isaacsim_dir}." - "\n\tIsaac Sim does not appear to be installed. VS Code settings will be generated" - "\n\twithout Isaac Sim extra paths." - ) - isaacsim_dir = "" +"""Path to the generated project's root directory.""" + -ISAACSIM_DIR = isaacsim_dir -"""Path to the isaac-sim directory.""" +def resolve_isaacsim_dir(isaac_path: str | None) -> str: + """Resolve the Isaac Sim installation directory. + Resolution order: the ``--isaac_path`` argument, then an ``import isaacsim`` probe using + the current interpreter, then the ``_isaac_sim`` symlink in the project root. -def overwrite_python_analysis_extra_paths(isaaclab_settings: str) -> str: - """Overwrite the python.analysis.extraPaths in the Isaac Lab settings file. + Args: + isaac_path: Explicit Isaac Sim path passed on the command line, or None. - The extraPaths are replaced with the path names from the isaac-sim settings file that exists in the - "{ISAACSIM_DIR}/.vscode/settings.json" file. + Returns: + The resolved Isaac Sim directory, or an empty string if none was found. + """ + if isaac_path and os.path.exists(isaac_path): + return isaac_path + # try to import isaacsim with the current interpreter to discover its install path + probe = subprocess.run( + [sys.executable, "-c", "import isaacsim; import os; print(os.environ.get('ISAAC_PATH', ''))"], + capture_output=True, + text=True, + check=False, + # avoid EULA prompt + stdin=subprocess.DEVNULL, + ) + if probe.returncode == 0 and probe.stdout.strip(): + return probe.stdout.strip() + # fall back to the ``_isaac_sim`` symlink used by binaries installations + fallback = os.path.join(ISAACLAB_DIR, "_isaac_sim") + return fallback if os.path.exists(fallback) else "" - If the isaac-sim settings file does not exist, the extraPaths are not overwritten. + +def build_extra_paths(isaacsim_dir: str) -> list[str]: + """Build the Pyright ``extraPaths`` for the project. + + The list combines the Isaac Sim kit-extension paths (parsed from Isaac Sim's own + ``.vscode/settings.json``) with the project's ``source/`` packages. All paths are + returned relative to the project root, using forward slashes. Args: - isaaclab_settings: The settings string to use as template. + isaacsim_dir: The Isaac Sim installation directory, or an empty string. Returns: - The settings string with overwritten python analysis extra paths. + The list of extra search paths. """ - # isaac-sim settings - isaacsim_vscode_filename = os.path.join(ISAACSIM_DIR, ".vscode", "settings.json") + path_names: list[str] = [] - # we use the isaac-sim settings file to get the python.analysis.extraPaths for kit extensions - # if this file does not exist, we will not add any extra paths - if ISAACSIM_DIR and os.path.exists(isaacsim_vscode_filename): - # read the path names from the isaac-sim settings file + # kit-extension paths, parsed from Isaac Sim's own vscode settings + isaacsim_vscode_filename = os.path.join(isaacsim_dir, ".vscode", "settings.json") + if isaacsim_dir and os.path.exists(isaacsim_vscode_filename): with open(isaacsim_vscode_filename) as f: vscode_settings = f.read() - # extract the path names - # search for the python.analysis.extraPaths section and extract the contents - settings = re.search( + # extract the contents of the python.analysis.extraPaths section + match = re.search( r"\"python.analysis.extraPaths\": \[.*?\]", vscode_settings, flags=re.MULTILINE | re.DOTALL ) - settings = settings.group(0) - settings = settings.split('"python.analysis.extraPaths": [')[-1] - settings = settings.split("]")[0] - - # read the path names from the isaac-sim settings file - path_names = settings.split(",") - path_names = [path_name.strip().strip('"') for path_name in path_names] - path_names = [path_name for path_name in path_names if len(path_name) > 0] - - # change the path names to be relative to the Isaac Lab directory - rel_path = os.path.relpath(ISAACSIM_DIR, ISAACLAB_DIR) - path_names = ['"${workspaceFolder}/' + rel_path + "/" + path_name + '"' for path_name in path_names] + if match: + body = match.group(0).split('"python.analysis.extraPaths": [')[-1].split("]")[0] + kit_paths = [p.strip().strip('"') for p in body.split(",")] + kit_paths = [p for p in kit_paths if p] + # make the paths relative to the project root + rel_path = os.path.relpath(isaacsim_dir, ISAACLAB_DIR) + path_names.extend(os.path.join(rel_path, p) for p in kit_paths) else: - path_names = [] + print( + "[WARN] Could not find Isaac Sim's .vscode/settings.json." + "\n\tKit-extension paths (omni.*, pxr.*, isaacsim.*) will not be added." + "\n\tPass --isaac_path to enable them." + ) - # add the path names that are in the Isaac Lab extensions directory - isaaclab_extensions = os.listdir(os.path.join(ISAACLAB_DIR, "source")) - path_names.extend(['"${workspaceFolder}/source/' + ext + '"' for ext in isaaclab_extensions]) + # the project's own source packages + source_dir = os.path.join(ISAACLAB_DIR, "source") + if os.path.exists(source_dir): + path_names.extend(os.path.join("source", ext) for ext in os.listdir(source_dir)) - # combine them into a single string - path_names = ",\n\t\t".expandtabs(4).join(path_names) - # deal with the path separator being different on Windows and Unix - path_names = path_names.replace("\\", "/") + # normalize to forward slashes so the config is valid on Windows too + return [p.replace("\\", "/") for p in path_names] - # replace the path names in the Isaac Lab settings file with the path names parsed - isaaclab_settings = re.sub( - r"\"python.analysis.extraPaths\": \[.*?\]", - '"python.analysis.extraPaths": [\n\t\t'.expandtabs(4) + path_names + "\n\t]".expandtabs(4), - isaaclab_settings, - flags=re.DOTALL, - ) - # return the Isaac Lab settings string - return isaaclab_settings + +def write_pyright_config(extra_paths: list[str]) -> None: + """Write ``pyrightconfig.json`` at the project root. + + The config is read by Pylance (VS Code) and basedpyright (Cursor). It takes precedence + over any ``[tool.pyright]`` table in ``pyproject.toml``, so the reporting defaults below + keep the dynamically loaded kit extensions from producing missing-import noise. + + Args: + extra_paths: The extra search paths to add, relative to the project root. + """ + config = { + "extraPaths": extra_paths, + "typeCheckingMode": "basic", + "reportMissingImports": "none", + "reportMissingModuleSource": "none", + } + pyright_config_filename = os.path.join(ISAACLAB_DIR, "pyrightconfig.json") + with open(pyright_config_filename, "w") as f: + f.write(json.dumps(config, indent=4) + "\n") def overwrite_default_python_interpreter(isaaclab_settings: str) -> str: @@ -148,6 +167,14 @@ def overwrite_default_python_interpreter(isaaclab_settings: str) -> str: def main(): + parser = argparse.ArgumentParser(description="Set up VS Code / Cursor settings for the project.") + parser.add_argument("--isaac_path", default=None, help="Absolute path to the Isaac Sim installation.") + args, _ = parser.parse_known_args() + + # resolve the Isaac Sim directory and write the editor-agnostic pyright config + isaacsim_dir = resolve_isaacsim_dir(args.isaac_path) + write_pyright_config(build_extra_paths(isaacsim_dir)) + # Isaac Lab template settings isaaclab_vscode_template_filename = os.path.join(ISAACLAB_DIR, ".vscode", "tools", "settings.template.json") # make sure the Isaac Lab template settings file exists @@ -159,11 +186,9 @@ def main(): with open(isaaclab_vscode_template_filename) as f: isaaclab_template_settings = f.read() - # overwrite the python.analysis.extraPaths in the Isaac Lab settings file with the path names - isaaclab_settings = overwrite_python_analysis_extra_paths(isaaclab_template_settings) # overwrite the default python interpreter in the Isaac Lab settings file with the path to the # python interpreter used to call this script - isaaclab_settings = overwrite_default_python_interpreter(isaaclab_settings) + isaaclab_settings = overwrite_default_python_interpreter(isaaclab_template_settings) # add template notice to the top of the file header_message = ( diff --git a/tools/template/templates/external/README.md b/tools/template/templates/external/README.md index 3e1bf79c73e6..f92f008b572f 100644 --- a/tools/template/templates/external/README.md +++ b/tools/template/templates/external/README.md @@ -63,14 +63,22 @@ It allows you to develop in an isolated environment, outside of the core Isaac L ### Set up IDE (Optional) -To setup the IDE, please follow these instructions: - -- Run VSCode Tasks, by pressing `Ctrl+Shift+P`, selecting `Tasks: Run Task` and running the `setup_python_env` in the drop down menu. - When running this task, you will be prompted to add the absolute path to your Isaac Sim installation. - -If everything executes correctly, it should create a file .python.env in the `.vscode` directory. -The file contains the python paths to all the extensions provided by Isaac Sim and Omniverse. -This helps in indexing all the python modules for intelligent suggestions while writing code. +Isaac Lab APIs (`isaaclab.*`) and this project's own package resolve automatically once you +point your editor at the Python interpreter that has Isaac Lab installed and run the editable +install from above (`python -m pip install -e source/{{ name }}`). This gives autocompletion, +docstrings, and go-to-definition into the Isaac Lab source, and works in both VS Code (Pylance) +and Cursor (basedpyright). + +To additionally get type information for the Isaac Sim kit extensions (`omni.*`, `pxr.*`, +`isaacsim.*`), run the `setup_python_env` task: press `Ctrl+Shift+P`, select `Tasks: Run Task`, +and run `setup_python_env`. You will be prompted for the absolute path to your Isaac Sim +installation. This generates a `pyrightconfig.json` at the project root (git-ignored) that adds +the kit-extension search paths for the language server. + +> **Using Cursor?** Cursor cannot run Pylance (it is licensed for official VS Code builds only), +> so install the [basedpyright](https://marketplace.visualstudio.com/items?itemName=detachhead.basedpyright) +> extension (`detachhead.basedpyright`) as the language server. It reads the same +> `pyrightconfig.json`, so type information works there without any extra setup. ### Setup as Omniverse Extension (Optional) From d0d5e681874e07cf95f6bfbbbde938cf4771bafc Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Fri, 4 Sep 2026 13:21:17 -0700 Subject: [PATCH 2/5] Discover Isaac Lab source packages with Pyright glob --- pyproject.toml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 09d1ebc6a2e1..81449f0f5829 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -325,24 +325,8 @@ exclude = [ # Make the in-repo packages resolvable by the language server (Pylance / basedpyright) # without an editable install, so imports like ``isaaclab.assets`` work out of the box. -# These are machine-independent relative paths. Add new source packages here when created. -extraPaths = [ - "source/isaaclab", - "source/isaaclab_assets", - "source/isaaclab_contrib", - "source/isaaclab_experimental", - "source/isaaclab_mimic", - "source/isaaclab_newton", - "source/isaaclab_ov", - "source/isaaclab_ovphysx", - "source/isaaclab_physx", - "source/isaaclab_ppisp", - "source/isaaclab_rl", - "source/isaaclab_tasks", - "source/isaaclab_tasks_experimental", - "source/isaaclab_teleop", - "source/isaaclab_visualizers", -] +# The glob keeps new source packages discoverable without maintaining a duplicate package list. +extraPaths = ["source/*"] typeCheckingMode = "basic" pythonVersion = "3.12" From 7dbb7cc99da09e4c73aeb4a6caedc83be27fbcd3 Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Fri, 4 Sep 2026 13:22:24 -0700 Subject: [PATCH 3/5] Reject invalid Isaac Sim editor paths --- source/isaaclab/isaaclab/utils/vscode.py | 15 ++++++++++----- .../isaaclab_rl/test/test_template_generator.py | 10 +++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/source/isaaclab/isaaclab/utils/vscode.py b/source/isaaclab/isaaclab/utils/vscode.py index 3b0096cdac45..986833531058 100644 --- a/source/isaaclab/isaaclab/utils/vscode.py +++ b/source/isaaclab/isaaclab/utils/vscode.py @@ -30,12 +30,12 @@ def resolve_isaacsim_dir(project_dir: pathlib.Path, isaac_path: str | None = Non """ if isaac_path: explicit_path = pathlib.Path(isaac_path).expanduser() - if not explicit_path.is_dir(): - raise ValueError(f"Isaac Sim directory does not exist: {explicit_path}") + if not _is_isaacsim_dir(explicit_path): + raise ValueError(f"Not an Isaac Sim directory (missing .vscode/settings.json): {explicit_path}") return explicit_path.resolve() env_path = os.environ.get("ISAAC_PATH") - if env_path and pathlib.Path(env_path).is_dir(): + if env_path and _is_isaacsim_dir(pathlib.Path(env_path)): return pathlib.Path(env_path).resolve() probe = subprocess.run( @@ -47,11 +47,11 @@ def resolve_isaacsim_dir(project_dir: pathlib.Path, isaac_path: str | None = Non ) for line in reversed(probe.stdout.splitlines()): candidate = pathlib.Path(line.strip()).expanduser() - if line.strip() and candidate.is_dir(): + if line.strip() and _is_isaacsim_dir(candidate): return candidate.resolve() fallback = project_dir / "_isaac_sim" - return fallback.resolve() if fallback.is_dir() else None + return fallback.resolve() if _is_isaacsim_dir(fallback) else None def read_isaacsim_extra_paths(isaacsim_dir: pathlib.Path | None) -> list[pathlib.Path]: @@ -146,3 +146,8 @@ def write_pyright_config(project_dir: pathlib.Path, extra_paths: list[str]): if (project_dir / "pyproject.toml").is_file(): config["extends"] = "./pyproject.toml" (project_dir / "pyrightconfig.json").write_text(json.dumps(config, indent=4) + "\n", encoding="utf-8") + + +def _is_isaacsim_dir(path: pathlib.Path) -> bool: + """Check whether a directory contains the settings used for extension discovery.""" + return path.is_dir() and (path / ".vscode" / "settings.json").is_file() diff --git a/source/isaaclab_rl/test/test_template_generator.py b/source/isaaclab_rl/test/test_template_generator.py index e750fba22db7..b72eb5e3062d 100644 --- a/source/isaaclab_rl/test/test_template_generator.py +++ b/source/isaaclab_rl/test/test_template_generator.py @@ -343,10 +343,14 @@ def test_vscode_setup_combines_simulator_local_and_installed_paths(tmp_path, mon ] -def test_vscode_setup_rejects_invalid_explicit_isaac_sim_path(tmp_path): +@pytest.mark.parametrize("path_exists", [False, True]) +def test_vscode_setup_rejects_invalid_explicit_isaac_sim_path(tmp_path, path_exists): """An invalid user-selected installation must not silently select a different Isaac Sim.""" - with pytest.raises(ValueError, match="Isaac Sim directory does not exist"): - vscode_utils.resolve_isaacsim_dir(tmp_path, str(tmp_path / "missing")) + invalid_path = tmp_path / "invalid" + if path_exists: + invalid_path.mkdir() + with pytest.raises(ValueError, match="Not an Isaac Sim directory"): + vscode_utils.resolve_isaacsim_dir(tmp_path, str(invalid_path)) def _all_libraries() -> list[dict]: From b486fe19626d6741ad0503a6bcbfac1bfc4fdc9e Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Fri, 4 Sep 2026 13:42:59 -0700 Subject: [PATCH 4/5] Generalize editor configuration module name --- .vscode/tools/setup_vscode.py | 2 +- source/isaaclab/isaaclab/__main__.py | 2 +- .../isaaclab/isaaclab/utils/{vscode.py => editor.py} | 2 +- source/isaaclab_rl/test/test_template_generator.py | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) rename source/isaaclab/isaaclab/utils/{vscode.py => editor.py} (98%) diff --git a/.vscode/tools/setup_vscode.py b/.vscode/tools/setup_vscode.py index 9fee8d8c2e29..42f5507e2f68 100644 --- a/.vscode/tools/setup_vscode.py +++ b/.vscode/tools/setup_vscode.py @@ -16,7 +16,7 @@ import re import sys -from isaaclab.utils.vscode import build_extra_paths, resolve_isaacsim_dir, write_pyright_config +from isaaclab.utils.editor import build_extra_paths, resolve_isaacsim_dir, write_pyright_config PROJECT_DIR = pathlib.Path(__file__).parents[2] """Path to the repository or generated project's root directory.""" diff --git a/source/isaaclab/isaaclab/__main__.py b/source/isaaclab/isaaclab/__main__.py index c430159faa10..781ba02b96c9 100644 --- a/source/isaaclab/isaaclab/__main__.py +++ b/source/isaaclab/isaaclab/__main__.py @@ -7,7 +7,7 @@ import pathlib import sys -from isaaclab.utils.vscode import build_extra_paths, resolve_isaacsim_dir, write_pyright_config +from isaaclab.utils.editor import build_extra_paths, resolve_isaacsim_dir, write_pyright_config VSCODE_SETTINGS_TEMPLATE = """ { diff --git a/source/isaaclab/isaaclab/utils/vscode.py b/source/isaaclab/isaaclab/utils/editor.py similarity index 98% rename from source/isaaclab/isaaclab/utils/vscode.py rename to source/isaaclab/isaaclab/utils/editor.py index 986833531058..854b175f19f4 100644 --- a/source/isaaclab/isaaclab/utils/vscode.py +++ b/source/isaaclab/isaaclab/utils/editor.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: BSD-3-Clause -"""Utilities for generating Pyright import paths for Isaac Lab projects.""" +"""Utilities for generating editor import paths for Isaac Lab projects.""" import importlib.metadata import importlib.util diff --git a/source/isaaclab_rl/test/test_template_generator.py b/source/isaaclab_rl/test/test_template_generator.py index b72eb5e3062d..a80ebec3e3df 100644 --- a/source/isaaclab_rl/test/test_template_generator.py +++ b/source/isaaclab_rl/test/test_template_generator.py @@ -18,7 +18,7 @@ import pytest import tomllib -from isaaclab.utils import vscode as vscode_utils +from isaaclab.utils import editor as editor_utils ROOT_DIR = Path(__file__).resolve().parents[3] TEMPLATE_TOOL_DIR = ROOT_DIR / "tools" / "template" @@ -328,10 +328,10 @@ def test_vscode_setup_combines_simulator_local_and_installed_paths(tmp_path, mon installed_root = tmp_path / "editable" / "isaaclab" installed_root.mkdir(parents=True) - monkeypatch.setattr(vscode_utils, "find_isaaclab_package_paths", lambda: [installed_root]) + monkeypatch.setattr(editor_utils, "find_isaaclab_package_paths", lambda: [installed_root]) - extra_paths = vscode_utils.build_extra_paths(project_dir, isaacsim_dir) - vscode_utils.write_pyright_config(project_dir, extra_paths) + extra_paths = editor_utils.build_extra_paths(project_dir, isaacsim_dir) + editor_utils.write_pyright_config(project_dir, extra_paths) config = json.loads((project_dir / "pyrightconfig.json").read_text()) assert config["extends"] == "./pyproject.toml" @@ -350,7 +350,7 @@ def test_vscode_setup_rejects_invalid_explicit_isaac_sim_path(tmp_path, path_exi if path_exists: invalid_path.mkdir() with pytest.raises(ValueError, match="Not an Isaac Sim directory"): - vscode_utils.resolve_isaacsim_dir(tmp_path, str(invalid_path)) + editor_utils.resolve_isaacsim_dir(tmp_path, str(invalid_path)) def _all_libraries() -> list[dict]: From cb3f41e57fc6bf924031e04e12b82cb80fd0cfcf Mon Sep 17 00:00:00 2001 From: Mustafa Haiderbhai Date: Fri, 4 Sep 2026 16:08:38 -0700 Subject: [PATCH 5/5] Clarify editor setup across installation workflows --- .../developer-tools/template_generator.rst | 5 + .../overview/developer-guide/vs_code.rst | 167 ++++++++++++------ docs/source/setup/quickstart.rst | 20 +++ tools/template/templates/external/README.md | 4 + 4 files changed, 146 insertions(+), 50 deletions(-) diff --git a/docs/source/developer-tools/template_generator.rst b/docs/source/developer-tools/template_generator.rst index 46f2f009418e..80fb06e50439 100644 --- a/docs/source/developer-tools/template_generator.rst +++ b/docs/source/developer-tools/template_generator.rst @@ -259,6 +259,11 @@ the configuration: uv run --extra isaacsim python .vscode/tools/setup_vscode.py +In VS Code, use Pylance and select the interpreter that ran the setup command. +In Cursor, install the ``detachhead.basedpyright`` extension instead of Pylance, +select the same interpreter, and reload the window. Both language servers read +the generated ``pyrightconfig.json``. + Create an internal task ----------------------- diff --git a/docs/source/overview/developer-guide/vs_code.rst b/docs/source/overview/developer-guide/vs_code.rst index a3d3456fcada..330d5d9a0714 100644 --- a/docs/source/overview/developer-guide/vs_code.rst +++ b/docs/source/overview/developer-guide/vs_code.rst @@ -1,11 +1,15 @@ .. _setup-vs-code: -Setting up Visual Studio Code ------------------------------ +Setting up VS Code or Cursor +---------------------------- -**This is optional. You do not need to use VScode to use Isaac Lab** +Editor setup is optional and is not required to run Isaac Lab. The repository +includes shared settings for `Visual Studio Code `_ +and compatible editors such as `Cursor `_. Complete one +of the :ref:`Isaac Lab installation methods ` before +configuring your editor. -`Visual Studio Code `_ has proven an invaluable tool for the development of Isaac Lab. The Isaac Lab repository includes the VSCode files for setting up your development environment. These are included in the ``.vscode`` directory and include the following files: +The ``.vscode`` directory contains the checked-in templates and tasks: .. code-block:: bash @@ -15,58 +19,123 @@ Setting up Visual Studio Code │   ├── settings.template.json │   └── setup_vscode.py ├── extensions.json - ├── launch.json # <- this is generated by setup_vscode.py - ├── settings.json # <- this is generated by setup_vscode.py + ├── launch.json # generated by setup_vscode.py + ├── settings.json # generated by setup_vscode.py └── tasks.json +Configure a source checkout +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. attention:: +Open the Isaac Lab repository root in your editor. Then run the setup command +that matches your installation from a terminal in that directory. - The following instructions on setting up Visual Studio Code only work with - :ref:`Isaac Sim Binaries Installation ` and not with - :ref:`Python Environment with Isaac Sim `. +.. tab-set:: + .. tab-item:: uv (recommended) -To setup the IDE, please follow these instructions: + For the default Newton environment, run: -1. Open the ``IsaacLab`` directory on Visual Studio Code IDE -2. Run VSCode `Tasks `__, by - pressing ``Ctrl+Shift+P``, selecting ``Tasks: Run Task`` and running the - ``setup_python_env`` in the drop down menu. + .. code-block:: bash - .. image:: ../../_static/vscode_tasks.png - :width: 600px - :align: center - :alt: VSCode Tasks + uv run python .vscode/tools/setup_vscode.py + If you use Isaac Sim from the ``isaacsim`` extra, include the extra so the + setup command can discover its extensions: -.. note:: - If this is your first time running tasks in VS Code, you may be prompted to select how to handle warnings. Simply follow - the prompts until the task window closes. + .. code-block:: bash -If everything executes correctly, it should create the following files: + uv run --extra isaacsim python .vscode/tools/setup_vscode.py -* ``.vscode/launch.json``: Contains the launch configurations for debugging python code. -* ``.vscode/settings.json``: Contains the settings for the python interpreter and the python environment. -* ``pyrightconfig.json``: Contains machine-local import paths for Pyright-compatible language servers. + .. tab-item:: Activated Python environment -.. note:: + Activate the uv, venv, or conda environment where Isaac Lab is installed, + then run: - Type information for the in-repository Isaac Lab packages (``isaaclab``, ``isaaclab_tasks``, ...) - works before running this task because their source roots are registered in ``pyproject.toml``. - The task generates a git-ignored ``pyrightconfig.json`` that inherits those settings and adds the - Isaac Sim extensions (``omni.*``, ``pxr.*``, ``isaacsim.*``) plus Isaac Lab packages discovered - in the active Python environment. This also supports editable and wheel installations. + .. code-block:: bash -.. note:: + python .vscode/tools/setup_vscode.py - **Using Cursor?** Cursor cannot run Pylance (it is licensed for official VS Code builds only), so - install the `basedpyright `__ - extension (``detachhead.basedpyright``) as the language server. It reads the same Pyright - configuration, so Isaac Lab type information works there without any extra setup. + .. tab-item:: Downloaded Isaac Sim package -For more information on VSCode support for Omniverse, please refer to the -following links: + Run the setup script through the Isaac Lab launcher after completing the + :ref:`downloaded package installation `: + + .. tab-set:: + :sync-group: os + + .. tab-item:: :icon:`fa-brands fa-linux` Linux + :sync: linux + + .. code-block:: bash + + ./isaaclab.sh -p .vscode/tools/setup_vscode.py + + .. tab-item:: :icon:`fa-brands fa-windows` Windows + :sync: windows + + .. code-block:: batch + + isaaclab.bat -p .vscode\tools\setup_vscode.py + + The ``setup_python_env`` task in the command palette runs the same launcher + workflow for a downloaded package. + +The command creates or updates these machine-local files: + +* ``.vscode/launch.json``: Debugging configurations. An existing file is preserved. +* ``.vscode/settings.json``: The interpreter and shared editor settings. +* ``pyrightconfig.json``: Import paths for Pyright-compatible language servers. + +The generated files are ignored by Git because interpreter and extension paths +vary between machines. Rerun the command after changing Python environments or +Isaac Sim installations. If Isaac Sim is not installed, the command prints a +warning and still configures the local Isaac Lab packages. + +The checked-in ``[tool.pyright]`` table in ``pyproject.toml`` makes packages +under ``source`` available immediately after cloning. The generated +``pyrightconfig.json`` inherits that policy and adds Isaac Sim extensions plus +Isaac Lab packages found in the active Python environment. This covers source, +editable, and wheel installations without storing absolute paths in Git. + +Configure VS Code +^^^^^^^^^^^^^^^^^ + +Install the extensions recommended by the repository when VS Code prompts you. +At minimum, install the Python and Pylance extensions. Run the setup command +above, then use **Python: Select Interpreter** from the command palette to select +the same interpreter used by the command. For the recommended uv installation, +this is ``.venv/bin/python`` on Linux or ``.venv\Scripts\python.exe`` on Windows. + +Configure Cursor +^^^^^^^^^^^^^^^^ + +Cursor cannot use Pylance because Pylance is licensed for official VS Code +builds. Install the Python extension and the `basedpyright +`__ +extension (``detachhead.basedpyright``). Then: + +1. Run the same setup command shown above for your installation. +2. Select the interpreter that ran the command. +3. Reload the Cursor window so basedpyright rereads ``pyrightconfig.json``. + +No Cursor-specific path list is required. Pylance and basedpyright read the +same Pyright configuration. + +Troubleshoot editor imports +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If an import is still unresolved: + +1. Confirm the selected editor interpreter matches ``python`` in the setup command. +2. Rerun setup with ``--extra isaacsim`` if the missing import is from + ``omni``, ``pxr``, or ``isaacsim``. +3. Reload the editor window. +4. Inspect the generated ``extraPaths`` in the root ``pyrightconfig.json``. + +Remove simulator extension directories that the project does not use if +language-server indexing consumes too much memory. + +For more information about VS Code support in Isaac Sim, see: * `Isaac Sim VSCode support `__ @@ -100,26 +169,24 @@ To use it: and press the green play button or ``F5``. VS Code will connect to the debugpy server running on ``localhost:3000``. -Configuring the python interpreter +Configuring the Python interpreter ---------------------------------- -In the provided configuration, we set the default python interpreter to use the -python executable provided by Omniverse. This is specified in the -``.vscode/settings.json`` file: +The setup command records the interpreter that ran it in +``.vscode/settings.json``. For example, a uv source checkout on Linux uses: .. code-block:: json { - "python.defaultInterpreterPath": "${workspaceFolder}/_isaac_sim/python.sh", + "python.defaultInterpreterPath": "/path/to/IsaacLab/.venv/bin/python", } -If you want to use a different python interpreter (for instance, from your conda or uv environment), -you need to change the python interpreter used by selecting and activating the python interpreter -of your choice in the bottom left corner of VSCode, or opening the command palette (``Ctrl+Shift+P``) -and selecting ``Python: Select Interpreter``. +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. -For more information on how to set python interpreter for VSCode, please -refer to the `VSCode documentation `_. +For more information about selecting a Python interpreter, see the +`VS Code documentation `_. Setting up formatting and linting diff --git a/docs/source/setup/quickstart.rst b/docs/source/setup/quickstart.rst index 2934b2097e35..4270c6e48727 100644 --- a/docs/source/setup/quickstart.rst +++ b/docs/source/setup/quickstart.rst @@ -36,6 +36,26 @@ Training outputs, including checkpoints, are saved under ``logs/``. Add uv run isaaclab train --help +Configure an editor (optional) +------------------------------ + +To enable import completion and debugging in VS Code or Cursor, generate the +machine-local editor configuration from the repository root: + +.. code-block:: bash + + uv run python .vscode/tools/setup_vscode.py + +If you use the ``isaacsim`` extra, include it so the command can discover the +Isaac Sim extensions: + +.. code-block:: bash + + uv run --extra isaacsim python .vscode/tools/setup_vscode.py + +VS Code uses Pylance. Cursor users should install basedpyright instead. See +:ref:`setup-vs-code` for complete editor and troubleshooting instructions. + .. The quickstart media is generated by tools/docs/media/generate_quickstart.sh. .. figure:: https://download.isaacsim.omniverse.nvidia.com/isaaclab/images/quickstart_task_categories.gif diff --git a/tools/template/templates/external/README.md b/tools/template/templates/external/README.md index ac1a61b61dc0..44ec3f479c59 100644 --- a/tools/template/templates/external/README.md +++ b/tools/template/templates/external/README.md @@ -86,6 +86,10 @@ configuration inherits the project's checked-in Pyright settings and adds the Is and any Isaac Lab packages discovered in the active Python environment. This supports both Pylance in VS Code and basedpyright in Cursor. +In VS Code, use Pylance and select the interpreter that ran the setup command. In Cursor, install the +[basedpyright extension](https://marketplace.visualstudio.com/items?itemName=detachhead.basedpyright) instead of +Pylance, select the same interpreter, and reload the window. Both language servers read `pyrightconfig.json`. + When using the `isaacsim` extra, include it while generating the editor configuration so the command can discover the Isaac Sim installation: