201 lines
8.4 KiB
Python
201 lines
8.4 KiB
Python
# 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
|
|
|
|
"""This script sets up the vs-code settings for the Isaac Lab project.
|
|
|
|
This script merges the python.analysis.extraPaths from the "{ISAACSIM_DIR}/.vscode/settings.json" file into
|
|
the ".vscode/settings.json" file.
|
|
|
|
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.
|
|
"""
|
|
|
|
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 = ""
|
|
|
|
ISAACSIM_DIR = isaacsim_dir
|
|
"""Path to the isaac-sim directory."""
|
|
|
|
|
|
def overwrite_python_analysis_extra_paths(isaaclab_settings: str) -> str:
|
|
"""Overwrite the python.analysis.extraPaths in the Isaac Lab settings file.
|
|
|
|
The extraPaths are replaced with the path names from the isaac-sim settings file that exists in the
|
|
"{ISAACSIM_DIR}/.vscode/settings.json" file.
|
|
|
|
If the isaac-sim settings file does not exist, the extraPaths are not overwritten.
|
|
|
|
Args:
|
|
isaaclab_settings: The settings string to use as template.
|
|
|
|
Returns:
|
|
The settings string with overwritten python analysis extra paths.
|
|
"""
|
|
# isaac-sim settings
|
|
isaacsim_vscode_filename = os.path.join(ISAACSIM_DIR, ".vscode", "settings.json")
|
|
|
|
# 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
|
|
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(
|
|
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]
|
|
else:
|
|
path_names = []
|
|
|
|
# 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])
|
|
|
|
# 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("\\", "/")
|
|
|
|
# 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 overwrite_default_python_interpreter(isaaclab_settings: str) -> str:
|
|
"""Overwrite the default python interpreter in the Isaac Lab settings file.
|
|
|
|
The default python interpreter is replaced with the path to the python interpreter used by the
|
|
isaac-sim project. This is necessary because the default python interpreter is the one shipped with
|
|
isaac-sim.
|
|
|
|
Args:
|
|
isaaclab_settings: The settings string to use as template.
|
|
|
|
Returns:
|
|
The settings string with overwritten default python interpreter.
|
|
"""
|
|
# read executable name
|
|
python_exe = sys.executable.replace("\\", "/")
|
|
|
|
# We make an exception for replacing the default interpreter if the
|
|
# path (/kit/python/bin/python3) indicates that we are using a local/container
|
|
# installation of IsaacSim. We will preserve the calling script as the default, python.sh.
|
|
# We want to use python.sh because it modifies LD_LIBRARY_PATH and PYTHONPATH
|
|
# (among other envars) that we need for all of our dependencies to be accessible.
|
|
if "kit/python/bin/python3" in python_exe:
|
|
return isaaclab_settings
|
|
# replace the default python interpreter in the Isaac Lab settings file with the path to the
|
|
# python interpreter in the Isaac Lab directory
|
|
isaaclab_settings = re.sub(
|
|
r"\"python.defaultInterpreterPath\": \".*?\"",
|
|
f'"python.defaultInterpreterPath": "{python_exe}"',
|
|
isaaclab_settings,
|
|
flags=re.DOTALL,
|
|
)
|
|
# return the Isaac Lab settings file
|
|
return isaaclab_settings
|
|
|
|
|
|
def main():
|
|
# 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
|
|
if not os.path.exists(isaaclab_vscode_template_filename):
|
|
raise FileNotFoundError(
|
|
f"Could not find the Isaac Lab template settings file: {isaaclab_vscode_template_filename}"
|
|
)
|
|
# read the Isaac Lab template settings file
|
|
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)
|
|
|
|
# add template notice to the top of the file
|
|
header_message = (
|
|
"// This file is a template and is automatically generated by the setup_vscode.py script.\n"
|
|
"// Do not edit this file directly.\n"
|
|
"// \n"
|
|
f"// Generated from: {isaaclab_vscode_template_filename}\n"
|
|
)
|
|
isaaclab_settings = header_message + isaaclab_settings
|
|
|
|
# write the Isaac Lab settings file
|
|
isaaclab_vscode_filename = os.path.join(ISAACLAB_DIR, ".vscode", "settings.json")
|
|
with open(isaaclab_vscode_filename, "w") as f:
|
|
f.write(isaaclab_settings)
|
|
|
|
# copy the launch.json file if it doesn't exist
|
|
isaaclab_vscode_launch_filename = os.path.join(ISAACLAB_DIR, ".vscode", "launch.json")
|
|
isaaclab_vscode_template_launch_filename = os.path.join(ISAACLAB_DIR, ".vscode", "tools", "launch.template.json")
|
|
if not os.path.exists(isaaclab_vscode_launch_filename):
|
|
# read template launch settings
|
|
with open(isaaclab_vscode_template_launch_filename) as f:
|
|
isaaclab_template_launch_settings = f.read()
|
|
# add header
|
|
header_message = header_message.replace(
|
|
isaaclab_vscode_template_filename, isaaclab_vscode_template_launch_filename
|
|
)
|
|
isaaclab_launch_settings = header_message + isaaclab_template_launch_settings
|
|
# write the Isaac Lab launch settings file
|
|
with open(isaaclab_vscode_launch_filename, "w") as f:
|
|
f.write(isaaclab_launch_settings)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|