Skip to content

[Cartpole] Remove deprecated task IDs#5851

Closed
hujc7 wants to merge 14 commits into
isaac-sim:developfrom
hujc7:jichuanh/cartpole-remove-deprecated-tasks
Closed

[Cartpole] Remove deprecated task IDs#5851
hujc7 wants to merge 14 commits into
isaac-sim:developfrom
hujc7:jichuanh/cartpole-remove-deprecated-tasks

Conversation

@hujc7

@hujc7 hujc7 commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Dependency

This PR is stacked on top of #5605. Until #5605 merges, the diff against
develop shows that PR's additions interleaved with this PR's deletions.
Once #5605 lands, the diff collapses to just the deletions + the
canonical-task repointing.

1. Removed

  1. 35 retired gym.register entries across the four cartpole init
    files:

    • direct/cartpole/__init__.py — 7 per-data-type camera IDs
    • manager_based/classic/cartpole/__init__.py — 4 per-pipeline IDs
    • direct/cartpole_showcase/cartpole/__init__.py — 15 per-shape IDs
    • direct/cartpole_showcase/cartpole_camera/__init__.py — 9 per-shape
      camera IDs
  2. The deprecated gym.register kwarg machinery:

    • parse_cfg.load_cfg_from_registry reverted to develop (no
      FutureWarning emit).
    • hydra.py _user_stacklevel narrowed back to file scope (the
      package-scoped widening was only needed to support warning
      attribution from parse_cfg).
  3. Stale references to retired task IDs in:

    • docs/source/features/reproducibility.rst
    • docs/source/how-to/optimize_stage_creation.rst
    • docs/source/overview/core-concepts/sensors/camera.rst
    • docs/source/overview/environments.rst
    • docs/source/overview/reinforcement-learning/performance_benchmarks.rst
    • scripts/reinforcement_learning/ray/hyperparameter_tuning/vision_cartpole_cfg.py
    • scripts/reinforcement_learning/ray/tuner.py
    • source/isaaclab/test/sensors/test_tiled_camera_env.py
    • source/isaaclab_tasks/test/test_preset_kit_decision.py
    • source/isaaclab_tasks/test/test_rendering_registered_tasks.py
    • source/isaaclab_tasks/test/test_train_scripts_deterministic.py
    • source/isaaclab_visualizers/test/test_visualizer_cartpole_integration.py
    • .github/workflows/test-multi-gpu.yaml
    • source/isaaclab_tasks/test/benchmarking/configs.yaml

2. Migration

Use the consolidated tasks with presets=<name>:

Removed Replacement
Isaac-Cartpole-{RGB,Depth,Albedo,SimpleShading-*}-Camera-Direct-v0, Isaac-Cartpole-Camera-Presets-Direct-v0 --task=Isaac-Cartpole-Camera-Direct-v0 [presets=<rgb|depth|albedo|simple_shading_*>]
Isaac-Cartpole-{RGB,Depth}-v0 --task=Isaac-Cartpole-Camera-v0 [presets=<rgb|depth>]
Isaac-Cartpole-RGB-{ResNet18,TheiaTiny}-v0 --task=Isaac-Cartpole-Camera-v0 --agent=rl_games_feature_cfg_entry_point presets=<resnet18|theia_tiny>
Isaac-Cartpole-Showcase-<Obs>-<Action>-Direct-v0 --task=Isaac-Cartpole-Showcase-Direct-v0 [--agent=skrl_<obs>_<action>_cfg_entry_point] presets=<obs>_<action>
Isaac-Cartpole-Camera-Showcase-<Obs>-<Action>-Direct-v0 --task=Isaac-Cartpole-Camera-Showcase-Direct-v0 [--agent=skrl_<obs>_<action>_cfg_entry_point] presets=<obs>_<action>

3. Test plan

hujc7 added 14 commits May 16, 2026 07:37
Collapse 35 per-variant Cartpole gym task IDs into 4 consolidated tasks
that select the variant via the typed preset CLI from isaac-sim#5587:

- Isaac-Cartpole-Camera-Direct-v0 (subsumes 7 Direct-backend perception IDs)
- Isaac-Cartpole-Camera-v0 (subsumes 4 manager-based perception IDs)
- Isaac-Cartpole-Showcase-Direct-v0 (subsumes 15 proprioceptive showcase IDs)
- Isaac-Cartpole-Camera-Showcase-Direct-v0 (subsumes 9 camera showcase IDs)

Variant selection moves from the gym ID to ``presets=<name>`` (plus
``physics=`` / ``renderer=`` on the Direct-backend camera task, and
``--agent=`` where the per-shape skrl / rl_games yaml differs from the
default). Each retired ID stays registered for one release with an
env_cfg_entry_point that emits a DeprecationWarning naming the new task
and the equivalent CLI tokens, then returns the corresponding cfg.

The shim machinery is factored into a new helper:

  isaaclab_tasks.utils.deprecated_task_alias(
      old_task_id, new_command, consolidated_cfg_path, cfg_factory=None
  )

which wraps the warning emission plus lazy cfg resolution behind the
``"module:Name"`` entry-point string convention gym uses elsewhere.

The consolidated PresetCfg classes live alongside their per-variant
siblings in the existing *_env_cfg.py files; no new wrapper modules.
PresetCfg's docstring now documents the underscore-prefix convention for
class-local helpers (the resolver already skips them).

Full per-ID migration table is in the PR description.
…presets

# Conflicts:
#	source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/__init__.py
#	source/isaaclab_tasks/isaaclab_tasks/direct/cartpole/cartpole_camera_presets_env_cfg.py
…ing IDs

The pre-existing develop consolidated ``MultiDataTypeCartpoleTiledCameraCfg``
uses a uniform identity-rotation camera for all data-type variants. The
historical per-variant cfgs (``CartpoleAlbedoCameraEnvCfg`` and the three
``CartpoleSimpleShading*CameraEnvCfg``) had a 180-degree rotated camera.
The merge from develop briefly reintroduced that rotation locally; the
rendering tests captured against develop's identity-rotation baseline
flagged the divergence on the consolidated path.

Drop the local rotation override so the consolidated cfg matches develop's
captured baseline. The deprecation shim returns the consolidated cfg
verbatim, so users of the retired task IDs now see the consolidated
camera orientation starting from this PR -- migration to the consolidated
task ID with ``presets=<name>`` carries that uniform pose anyway.

Test expectations updated accordingly.
Revert local extraction of `_CAMERA_CFG_PATH` / `_SHOWCASE_CFG_PATH`
constants and the small `_CAMERA_KWARGS` dict in the four cartpole
`__init__.py` files. Each `gym.register` block is again fully
self-contained (cfg-path string + skrl/rl_games entry points spelled
out in place), matching the per-block style on develop so the PR diff
shows only what is genuinely new (the alias call itself).

Pass `old_task_id=`, `new_command=`, and `consolidated_cfg_path=` as
keyword arguments at every call site -- a 3-arg positional invocation
is hard to read at the gym registration call sites.

No behavior change: the 73 cartpole deprecation tests still pass.
Change deprecated_task_alias(new_command=...) from a free-form string
to a list[str], where each list entry is one whitespace-separated CLI
token. The factory joins the list with single spaces when forming the
DeprecationWarning body, so the user-facing warning text is unchanged
in shape (still quoted, one command).

The list form makes per-token diffs easier to scan at the gym.register
call sites: each --task / --agent / presets= entry is on its own
line instead of being lost inside a multi-line implicit string
concat. Call-site convention: --task=... first, --agent=... next
when present, presets=NAME selector at the end -- the warning body
reads in that order too.

Test fixtures reordered to match the new --task / --agent / presets=
sequence in the warning body. All 73 cartpole deprecation tests pass.
Replace the custom flat-getattr + nested-setattr default resolution
inside deprecated_task_alias with a single call to
isaaclab_tasks.utils.hydra.resolve_presets(cls(), selected). The
resolver already walks every nested PresetCfg in the cfg tree and
picks the variant matching one of the selected names (falling back
to each preset's default field), which is exactly what the canonical
task's Hydra path does. The shim now returns bit-for-bit what the
canonical task plus presets=<name> would have produced.

Side effects:

* Drop the cfg_factory parameter from deprecated_task_alias -- the
  generic resolver handles the 2-axis (nested) case that previously
  required a custom callable.
* Delete the local _resolve_camera_variant helper from
  direct/cartpole/__init__.py and the cfg_factory= argument from
  its 5 deprecated-shim call sites.
* selected is now the union of every presets=NAME[,...] token's
  names, so a future caller passing presets=a,b correctly resolves
  both rather than truncating to the first.

No measurable startup-time delta: instantiation of the consolidated
PresetCfg (~22 ms, dominated by configclass deepcopy of a ~1400-node
tree) is the shared cost; the tree walk on top is sub-millisecond.
73 cartpole deprecation tests still pass.
…a cfgs

This is a two-part change driven by CI failures on the prior shim design:

1. ``test_preset_kit_decision`` (5 cases) failed because the shim's call to
   ``resolve_presets(cls(), selected)`` resolved every PresetCfg in the
   tree -- including ``sim.physics`` and ``tiled_camera.renderer_cfg`` --
   to their defaults when the shim's preset names did not match. Hydra's
   downstream validation then reported the user's ``physics=`` /
   ``renderer=`` CLI selectors as "Unknown preset(s)" because no
   PresetCfg remained to resolve them against.

2. ``test_rendering_registered_tasks`` (4 cases: Albedo + 3
   SimpleShading) failed because the consolidated cfg's matching variant
   does not carry the 180-degree camera rotation that the historical
   per-variant subclasses use (a long-standing latent divergence on
   develop between Style A subclasses and Style B consolidated cfg --
   the consolidation PR never reconciled it). Routing retired IDs
   through Style B silently dropped the rotation, so rendering
   baselines captured against Style A no longer matched.

Both regressions come from the same root cause: the shim was
re-resolving the consolidated cfg instead of returning the retired ID's
historical cfg verbatim.

The fix:

* ``deprecated_task_alias`` now takes a required ``cfg_factory``
  callable and drops ``consolidated_cfg_path`` + the in-shim
  ``resolve_presets`` call. Each retired task's shim returns whatever
  the factory builds.

* Every retired task call site passes ``cfg_factory=lambda: OldClass()``
  pointing at the historical per-variant subclass, so the retired ID
  stays bit-for-bit identical to develop. The deprecation warning is
  layered on top; no behavior change.

* The 4 manager-camera per-variant subclasses (deleted in an earlier
  attempt that consolidated them away) are restored alongside the new
  consolidated ``CartpoleCameraPresetsEnvCfg``. Both styles co-exist for
  one release, mirroring how the direct-camera files already work on
  develop. The consolidated cfg powers the canonical
  ``Isaac-Cartpole-Camera-v0`` task; the per-variant subclasses back the
  retired task IDs.

* The direct-camera ``CartpoleCameraPresetsEnvCfg`` keeps its earlier
  restructure (flat env cfg + nested PresetCfg fields for
  ``observation_space`` and ``tiled_camera.data_types``). The canonical
  ``Isaac-Cartpole-Camera-Direct-v0`` uses it; field-by-field equivalent
  to develop's consolidated cfg.

* ``hydra.py`` is unchanged from develop -- the earlier ``strict=``
  parameter is removed since the shim no longer calls
  ``resolve_presets``.

Each OLD per-variant subclass gets a docstring note pointing at the
canonical task + the migration command, marking it for removal alongside
the retired gym task ID after one release.

Tests:
* ``test_cartpole_preset_deprecations``: 73 pass (rotation expectations
  updated to reflect the historical 180-degree flip on Albedo /
  SimpleShading subclasses).
* ``test_preset_kit_decision``: 5 pass.
* ``test_manager_based_rl_env_obs_spaces``: imports
  ``CartpoleRGBCameraEnvCfg`` / ``CartpoleDepthCameraEnvCfg`` -- both
  remain present so the test is unaffected.
The consolidated ``CartpoleCameraPresetsEnvCfg`` was restructured from a
top-level ``PresetCfg`` (Style B on develop) into a flat
``DirectRLEnvCfg`` with nested ``PresetCfg`` fields. The visualizer
integration test extracted the rgb variant via
``getattr(env_cfg_root, "default", None)`` -- that path no longer exists
on the new shape and raises ``RuntimeError`` before any actual rendering.

Replace the ``default`` lookup with ``resolve_presets(env_cfg)`` so the
nested ``PresetCfg`` fields (observation_space, tiled_camera.data_types,
sim.physics, renderer_cfg) are resolved to their defaults in place,
matching how the canonical gym task ID resolves them at ``gym.make()``
time. The downstream test logic (overriding ``scene.num_envs``,
``viewer``, ``tiled_camera.width/height``, ``observation_space[2]``,
``sim.physics``, ``sim.visualizer_cfgs``) is unchanged.
…-state leak

Importing the historical per-variant cfg classes at the top of each
cartpole task ``__init__.py`` (so ``cfg_factory=lambda: SomeClass()``
could close over them) pulled ``isaaclab.envs``, ``isaaclab.scene``, and
their downstream modules into ``sys.modules`` *during*
``isaaclab_tasks.direct.cartpole``'s package import. That happens before
``AppLauncher._create_app`` runs, and AppLauncher's mod-cache cycle
``del sys.modules[key]`` + ``sys.modules[key] = value`` only restores
the ``sys.modules`` entries -- it never re-binds the submodules as
attributes on the parent ``isaaclab`` package. After the cycle,
``isaaclab.scene`` lives in ``sys.modules`` but ``isaaclab.scene``
``getattr`` on the ``isaaclab`` module raises ``AttributeError``, which
breaks any unrelated test that walks a dotted string path like
``monkeypatch.setattr("isaaclab.scene.interactive_scene.cloner.X", Y)``.

Concretely on this PR, both ``test_clone_environments_executes_*`` cases
in ``source/isaaclab/test/scene/test_interactive_scene.py`` started
failing once the eager imports landed. The same tests pass on develop
because there the cfg classes are only referenced via lazy
``"module:Class"`` strings in the gym entry points, so nothing imports
them before ``AppLauncher`` runs.

Fix: introduce a tiny ``_lazy_cfg(class_name, module=...)`` helper in
each of the four cartpole ``__init__.py`` files. The helper returns a
zero-arg callable that imports the cfg class via ``importlib`` only
when invoked. ``deprecated_task_alias`` still calls ``cfg_factory()``
exactly once per ``gym.make()``, so the deferred import path runs at
the same moment the eager-import path would have triggered (the
shim's factory body), just without the side effect of pre-loading the
cfg module before ``AppLauncher``.

Local verification:
* ``test_clone_environments_executes_env_root_plan_with_positions``: PASS
* ``test_clone_environments_executes_asset_level_plan_without_usd_positions``: PASS
* 73 cartpole-deprecation tests + 5 preset-kit-decision tests: all pass.
Limit this PR's scope to deprecating the per-variant cartpole task IDs in
favor of the four consolidated tasks; revert the cfg-class simplification
work that was an additional optimization.

- Revert direct/cartpole/cartpole_camera_presets_env_cfg.py to develop.
- Restructure manager-based and showcase consolidated cfgs as minimal
  PresetCfg wrappers that expose existing per-variant subclasses as
  preset variants. Drop the flat-cfg / nested-PresetCfg-field rewrite.
- Replace the cfg_factory + lazy_cfg machinery with a data-driven
  deprecated_alias_for kwarg on gym.register. parse_cfg.load_cfg_from_registry
  checks the kwarg and emits the DeprecationWarning when the retired ID's
  env_cfg_entry_point is loaded. env_cfg_entry_point stays a plain
  "module:Class" string, matching develop's pattern.
- Delete the now-unused task_deprecation.py utility and the
  test_cartpole_preset_deprecations.py test.
Replace flat ``deprecated_alias_for`` string kwarg on retired-task
``gym.register`` calls with a structured ``deprecated`` dict whose
``alias`` field holds the migration command. Keeps the kwarg shape open
for future fields (``reason``, ``removed_in``, ...) without renaming the
top-level key. ``parse_cfg.load_cfg_from_registry`` reads
``kwargs["deprecated"]["alias"]``; warning text and behavior unchanged.
DeprecationWarning + stacklevel=2 silently suppressed the warning in any
call path where the immediate caller of load_cfg_from_registry is a library
module (parse_env_cfg, hydra.register_task, isaaclab_contrib/isaaclab_mimic
wrappers). Python's default DeprecationWarning filter only displays warnings
attributed to __main__.

- Generalize hydra._user_stacklevel from file-scoped to package-scoped
  (walks past anything under isaaclab_tasks.utils.*) so a single helper
  serves callers in any utils submodule.
- Import _user_stacklevel from hydra into parse_cfg.load_cfg_from_registry
  and use it for the deprecation-alias warning.
- Switch the warning category from DeprecationWarning to FutureWarning so
  the warning is shown by Python's default filter regardless of attribution
  (the existing convention for end-user-facing deprecations in
  hydra.py preset aliases and manager_based_env / direct_rl_env cfg-field
  warnings).

Verified under default Python filter: paths 1 (direct call), 2
(parse_env_cfg from __main__), and 3 (third-party wrapper outside the
utils package) all display the warning.
Followup to isaac-sim#5605 which marked 35 per-variant Cartpole task IDs as
deprecated aliases for the four consolidated tasks. With 3.0 acting as
the breaking-changes window, drop the deprecation cycle entirely.

- Delete 35 retired gym.register entries across the four
  cartpole/cartpole_showcase __init__ files.
- Drop the ``deprecated`` gym.register kwarg machinery in
  parse_cfg.load_cfg_from_registry and the package-scoped
  _user_stacklevel widening in hydra.py.
- Repoint remaining references in docs, ray hyperparameter scripts,
  rendering/visualizer tests, the multi-GPU CI workflow, and the
  benchmark configs to the consolidated tasks.

Migrate to the consolidated tasks with presets=<name>:
Isaac-Cartpole-Camera-Direct-v0, Isaac-Cartpole-Camera-v0,
Isaac-Cartpole-Showcase-Direct-v0, and
Isaac-Cartpole-Camera-Showcase-Direct-v0.
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team infrastructure labels May 29, 2026

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Isaac Lab Review Bot

Summary

This PR cleanly removes 35 deprecated per-variant Cartpole task IDs as a follow-up to #5605, consolidating them into four canonical tasks:

  • Isaac-Cartpole-Camera-Direct-v0 (replaces 7 Direct-backend camera IDs)
  • Isaac-Cartpole-Camera-v0 (replaces 4 manager-based camera IDs)
  • Isaac-Cartpole-Showcase-Direct-v0 (replaces 15 proprioceptive showcase IDs)
  • Isaac-Cartpole-Camera-Showcase-Direct-v0 (replaces 9 camera showcase IDs)

The change is well-scoped for the 3.0 breaking-changes window, removing the deprecation cycle that was added in #5605.

Findings

🔵 Suggestion: Changelog fragment numbering
The optimize_stage_creation.rst doc still shows 20. for the next item after 5. when listing tasks:

4.  Isaac-Cartpole-Showcase-Direct-v0
5.  Isaac-Cartpole-v0
20. Isaac-Factory-GearMesh-Direct-v0

Consider renumbering for consistency.

🔵 Suggestion: Benchmark config reduction
The configs.yaml benchmarking file removed several task variants but only kept 2 consolidated entries (Isaac-Cartpole-Camera-Direct-v0 and Isaac-Cartpole-Camera-v0). This is likely intentional for simplification, but worth confirming that preset variants can still be benchmarked if needed via CLI overrides.

Breaking Change Documentation

Excellent - The PR includes:

  • A clear changelog fragment (jichuanh-cartpole-remove-deprecated-tasks.minor.rst) marked as Breaking
  • A comprehensive migration table in the PR description mapping every removed ID to its consolidated replacement with presets=<name> syntax
  • Clear explanation that 3.0 is the breaking-changes window

Completeness of Removal

All references properly cleaned up across:

  • 4 __init__.py task registration files (35 gym.register entries removed)
  • 6 documentation files updated
  • 2 Ray hyperparameter tuning scripts updated
  • 1 CI workflow file updated
  • 6 test files updated
  • 1 benchmark config updated
  • Deprecation machinery in parse_cfg.load_cfg_from_registry and hydra.py reverted

Test Coverage

✅ Appropriate for a removal PR:

  • test_rendering_registered_tasks.py updated to test the consolidated task with presets parameter
  • test_tiled_camera_env.py references updated
  • test_train_scripts_deterministic.py updated
  • test_preset_kit_decision.py updated
  • test_visualizer_cartpole_integration.py updated

CI Status

labeler check passed. Note: This PR is stacked on #5605, so full CI will be more meaningful after the base PR merges.

Verdict

No significant issues found. This is a clean breaking-change removal that:

  1. Properly removes all 35 deprecated task IDs
  2. Updates all references in docs, tests, scripts, and CI
  3. Provides clear migration documentation
  4. Is appropriately scoped for the 3.0 release window

The minor doc numbering issue is cosmetic. Ready to merge after #5605 lands and CI completes.

@kellyguo11 kellyguo11 moved this to In review in Isaac Lab May 30, 2026
@kellyguo11 kellyguo11 moved this from In review to In progress in Isaac Lab May 30, 2026
@kellyguo11

Copy link
Copy Markdown
Contributor

@fatimaanes for viz

@fatimaanes fatimaanes self-requested a review May 30, 2026 01:29
@hujc7

hujc7 commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

done in 8b01020

@hujc7 hujc7 closed this Jun 2, 2026
@github-project-automation github-project-automation Bot moved this from In progress to Done in Isaac Lab Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation infrastructure isaac-lab Related to Isaac Lab team

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants