Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
Thank you for your interest in sending a pull request. Please make sure to check the contribution guidelines.

Link: https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html

💡 Please try to keep PRs small and focused. Large PRs are harder to review and merge.
-->

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
Expand All @@ -21,8 +23,8 @@ is demanded by more than one party. -->

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
- This change requires a documentation update
- Breaking change (existing functionality will not work without user modification)
- Documentation update

## Screenshots

Expand All @@ -40,6 +42,7 @@ To upload images to a PR -- simply drag and drop an image while in edit mode and

## Checklist

- [ ] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format`
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
Expand Down
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"python": ("https://docs.python.org/3", None),
"numpy": ("https://numpy.org/doc/stable/", None),
"trimesh": ("https://trimesh.org/", None),
"torch": ("https://pytorch.org/docs/stable/", None),
"torch": ("https://docs.pytorch.org/docs/stable", None),
"isaacsim": ("https://docs.isaacsim.omniverse.nvidia.com/5.0.0/py/", None),
"gymnasium": ("https://gymnasium.farama.org/", None),
"warp": ("https://nvidia.github.io/warp/", None),
Expand Down Expand Up @@ -162,6 +162,7 @@
"isaacsim.core.api",
"isaacsim.core.cloner",
"isaacsim.core.version",
"isaacsim.core.utils",
"isaacsim.robot_motion.motion_generation",
"isaacsim.gui.components",
"isaacsim.asset.importer.urdf",
Expand Down
3 changes: 0 additions & 3 deletions docs/source/overview/environments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ for the lift-cube environment:
.. |gr1_pick_place| image:: ../_static/tasks/manipulation/gr-1_pick_place.jpg
.. |surface-gripper| image:: ../_static/tasks/manipulation/ur10_stack_surface_gripper.jpg
.. |gr1_pp_waist| image:: ../_static/tasks/manipulation/gr-1_pick_place_waist.jpg
.. |surface-gripper| image:: ../_static/tasks/manipulation/ur10_stack_surface_gripper.jpg
.. |galbot_stack| image:: ../_static/tasks/manipulation/galbot_stack_cube.jpg

.. |reach-franka-link| replace:: `Isaac-Reach-Franka-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/reach/config/franka/joint_pos_env_cfg.py>`__
Expand All @@ -177,8 +176,6 @@ for the lift-cube environment:
.. |short-suction-link| replace:: `Isaac-Stack-Cube-UR10-Short-Suction-IK-Rel-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/ur10_gripper/stack_ik_rel_env_cfg.py>`__
.. |gr1_pp_waist-link| replace:: `Isaac-PickPlace-GR1T2-WaistEnabled-Abs-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/pick_place/pickplace_gr1t2_waist_enabled_env_cfg.py>`__
.. |galbot_stack-link| replace:: `Isaac-Stack-Cube-Galbot-Left-Arm-Gripper-RmpFlow-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/galbot/stack_rmp_rel_env_cfg.py>`__
.. |long-suction-link| replace:: `Isaac-Stack-Cube-UR10-Long-Suction-IK-Rel-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/ur10_gripper/stack_ik_rel_env_cfg.py>`__
.. |short-suction-link| replace:: `Isaac-Stack-Cube-UR10-Short-Suction-IK-Rel-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/stack/config/ur10_gripper/stack_ik_rel_env_cfg.py>`__

.. |cube-shadow-link| replace:: `Isaac-Repose-Cube-Shadow-Direct-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/direct/shadow_hand/shadow_hand_env_cfg.py>`__
.. |cube-shadow-ff-link| replace:: `Isaac-Repose-Cube-Shadow-OpenAI-FF-Direct-v0 <https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab_tasks/isaaclab_tasks/direct/shadow_hand/shadow_hand_env_cfg.py>`__
Expand Down
112 changes: 108 additions & 4 deletions docs/source/refs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ Please ensure that your code is well-formatted, documented and passes all the te
Large pull requests are difficult to review and may take a long time to merge.


More details on the code style and testing can be found in the `Coding Style`_ and `Unit Testing`_ sections.


Contributing Documentation
--------------------------

Expand Down Expand Up @@ -237,6 +240,62 @@ For documentation, we adopt the `Google Style Guide <https://sphinxcontrib-napol
for docstrings. We use `Sphinx <https://www.sphinx-doc.org/en/master/>`__ for generating the documentation.
Please make sure that your code is well-documented and follows the guidelines.

Code Structure
^^^^^^^^^^^^^^

We follow a specific structure for the codebase. This helps in maintaining the codebase and makes it easier to
understand.

In a Python file, we follow the following structure:

.. code:: python

# Imports: These are sorted by the pre-commit hooks.
# Constants
# Functions (public)
# Classes (public)
# _Functions (private)
# _Classes (private)

Imports are sorted by the pre-commit hooks. Unless there is a good reason to do otherwise, please do not
import the modules inside functions or classes. To deal with circular imports, we use the
:obj:`typing.TYPE_CHECKING` variable. Please refer to the `Circular Imports`_ section for more details.

Python does not have a concept of private and public classes and functions. However, we follow the
convention of prefixing the private functions and classes with an underscore.
The public functions and classes are the ones that are intended to be used by the users. The private
functions and classes are the ones that are intended to be used internally in that file.
Irrespective of the public or private nature of the functions and classes, we follow the Style Guide
for the code and make sure that the code and documentation are consistent.

Similarly, within Python classes, we follow the following structure:

.. code:: python

# Constants
# Class variables (public or private): Must have the type hint ClassVar[type]
# Dunder methods: __init__, __del__
# Representation: __repr__, __str__
# Properties: @property
# Instance methods (public)
# Class methods (public)
# Static methods (public)
# _Instance methods (private)
# _Class methods (private)
# _Static methods (private)

The rule of thumb is that the functions within the classes are ordered in the way a user would
expect to use them. For instance, if the class contains the method :meth:`initialize`, :meth:`reset`,
:meth:`update`, and :meth:`close`, then they should be listed in the order of their usage.
The same applies for private functions in the class. Their order is based on the order of call inside the
class.

.. dropdown:: Code skeleton
:icon: code

.. literalinclude:: snippets/code_skeleton.py
:language: python

Circular Imports
^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -414,15 +473,47 @@ We summarize the key points below:


Unit Testing
^^^^^^^^^^^^
------------

We use `pytest <https://docs.pytest.org>`__ for unit testing.
Good tests not only cover the basic functionality of the code but also the edge cases.
They should be able to catch regressions and ensure that the code is working as expected.
Please make sure that you add tests for your changes.

.. tab-set::
:sync-group: os

.. tab-item:: :icon:`fa-brands fa-linux` Linux
:sync: linux

.. code-block:: bash

# Run all tests
./isaaclab.sh --test # or "./isaaclab.sh -t"

# Run all tests in a particular file
./isaaclab.sh -p -m pytest source/isaaclab/test/deps/test_torch.py

# Run a particular test
./isaaclab.sh -p -m pytest source/isaaclab/test/deps/test_torch.py::test_array_slicing

.. tab-item:: :icon:`fa-brands fa-windows` Windows
:sync: windows

.. code-block:: bash

# Run all tests
isaaclab.bat --test # or "isaaclab.bat -t"

# Run all tests in a particular file
isaaclab.bat -p -m pytest source/isaaclab/test/deps/test_torch.py

# Run a particular test
isaaclab.bat -p -m pytest source/isaaclab/test/deps/test_torch.py::test_array_slicing


Tools
^^^^^
-----

We use the following tools for maintaining code quality:

Expand All @@ -435,6 +526,19 @@ Please check `here <https://pre-commit.com/#install>`__ for instructions
to set these up. To run over the entire repository, please execute the
following command in the terminal:

.. code:: bash
.. tab-set::
:sync-group: os

.. tab-item:: :icon:`fa-brands fa-linux` Linux
:sync: linux

.. code-block:: bash

./isaaclab.sh --format # or "./isaaclab.sh -f"

.. tab-item:: :icon:`fa-brands fa-windows` Windows
:sync: windows

.. code-block:: bash

./isaaclab.sh --format # or "./isaaclab.sh -f"
isaaclab.bat --format # or "isaaclab.bat -f"
155 changes: 155 additions & 0 deletions docs/source/refs/snippets/code_skeleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

import os
import sys
from typing import ClassVar


DEFAULT_TIMEOUT: int = 30
"""Default timeout for the task."""

_MAX_RETRIES: int = 3 # private constant (note the underscore)
"""Maximum number of retries for the task."""


def run_task(task_name: str):
"""Run a task by name.

Args:
task_name: The name of the task to run.
"""
print(f"Running task: {task_name}")


class TaskRunner:
"""Runs and manages tasks."""

DEFAULT_NAME: ClassVar[str] = "runner"
"""Default name for the runner."""

_registry: ClassVar[dict] = {}
"""Registry of runners."""

def __init__(self, name: str):
"""Initialize the runner.

Args:
name: The name of the runner.
"""
self.name = name
self._tasks = [] # private instance variable

def __del__(self):
"""Clean up the runner."""
print(f"Cleaning up {self.name}")

def __repr__(self) -> str:
return f"TaskRunner(name={self.name!r})"

def __str__(self) -> str:
return f"TaskRunner: {self.name}"

"""
Properties.
"""

@property
def task_count(self) -> int:
return len(self._tasks)

"""
Operations.
"""

def initialize(self):
"""Initialize the runner."""
print("Initializing runner...")

def update(self, task: str):
"""Update the runner with a new task.

Args:
task: The task to add.
"""
self._tasks.append(task)
print(f"Added task: {task}")

def close(self):
"""Close the runner."""
print("Closing runner...")

"""
Operations: Registration.
"""

@classmethod
def register(cls, name: str, runner: "TaskRunner"):
"""Register a runner.

Args:
name: The name of the runner.
runner: The runner to register.
"""
if name in cls._registry:
_log_error(f"Runner {name} already registered. Skipping registration.")
return
cls._registry[name] = runner

@staticmethod
def validate_task(task: str) -> bool:
"""Validate a task.

Args:
task: The task to validate.

Returns:
True if the task is valid, False otherwise.
"""
return bool(task and task.strip())

"""
Internal operations.
"""

def _reset(self):
"""Reset the runner."""
self._tasks.clear()

@classmethod
def _get_registry(cls) -> dict:
"""Get the registry."""
return cls._registry

@staticmethod
def _internal_helper():
"""Internal helper."""
print("Internal helper called.")


"""
Helper operations.
"""


def _log_error(message: str):
"""Internal helper to log errors.

Args:
message: The message to log.
"""
print(f"[ERROR] {message}")


class _TaskHelper:
"""Private utility class for internal task logic."""

def compute(self) -> int:
"""Compute the result.

Returns:
The result of the computation.
"""
return 42
Loading