Fix kit-less container bugs and ship OVPhysX plus all Newton viewers - #6953
Fix kit-less container bugs and ship OVPhysX plus all Newton viewers#6953hujc7 wants to merge 7 commits into
Conversation
Every docker compose invocation ran with check=False and its return code was never inspected, so a failed build printed "Finished building the docker image" and exited 0. A permission or daemon error was therefore indistinguishable from success, leaving no non-zero exit and no error text to report. Route build, start, stop and config through a helper that inspects the return code and raises. copy() warns instead, since an absent artifact directory is normal. The two probe helpers and interactive enter() keep check=False deliberately: for them a non-zero code is the answer, or the exit belongs to the user's shell.
The image advertised Newton physics and OVRTX rendering but shipped only one of Newton's three viewers, and excluded OVPhysX entirely. OVPhysX was held out over a packaging pin: it caps packaging at <24 while ray, pulled in by rl[all], requires >=24.2. That cap is over-strict -- ovphysx's whole use of the library is a single 'from packaging.version import Version' -- so an override reconciles it, as it already does for other over-strict pins. viser and rerun are Newton viewers too (isaaclab_visualizers wraps newton.viewer.ViewerViser and ViewerRerun), so an image built around Newton now hosts all three. libxrender1 is added because pyglet's xlib backend resolves libXrender.so.1 at import time and nothing else in the runtime set pulls it in. The in-build assertions are inverted and extended so a future selector change cannot silently drop any of these again.
get_checkpoint_path documents 'Raises: ValueError: When no runs are found in the input directory', but os.scandir raises FileNotFoundError when the directory does not exist at all, and only IndexError was caught. Callers saw a bare traceback naming scandir rather than the intended message. Both cases mean the same thing to the caller: no runs.
The description listed Newton physics and OVRTX rendering and said the OVPhysX runtime was not included, which no longer matches the image. It also said no visualizer was selected without saying which ones are available, so the only way to learn that --viz viser or --viz rerun would work was to try them. State the shipped set, and name kit as the exception since it comes from Omniverse Kit, which this image does not contain.
Two independent breakages from the preceding commits. test_container_profiles patches subprocess.run with a bare MagicMock, so the return code container_interface now inspects was a mock attribute, never equal to 0, and the new guard raised. The mocks have to model a command that succeeded. test_dockerfile_nonroot pinned the old install selector and asserted 'ovphysx' not in names, which is the contract the image just stopped having. Renamed to match, and extended to cover the viewers and libxrender1 so a future selector change fails here rather than in a user's container.
The Dockerfile carried an eleven-line block restating the packaging/ray argument that pyproject.toml already makes beside the override itself, the same rationale appeared twice in adjacent pyproject blocks, and one comment was repeated verbatim at three mock sites. Keep each rationale in one place and let the assertions speak.
There was a problem hiding this comment.
Isaac Lab Review Bot
The Docker command wrapper correctly centralizes failure propagation, but its error-reporting path breaks for commands containing Path arguments, preventing the intended warning or RuntimeError.
- Design and architecture: Centralizing Docker invocation in
_run_docker_commandis appropriate, and thecheck=Falseoption preserves non-fatal artifact-copy behavior. The helper must support the argument types accepted by its call sites. - API: The intended behavior changes are coherent: Docker build/start/stop/config failures become non-zero exits, artifact-copy failures remain warnings, and
get_checkpoint_pathnow raises its documentedValueErrorfor a missing log directory. However, the Docker failure contract is not reliably met when command arguments include paths. - Implementation: At line 140,
' '.join(cmd)assumes every command element is a string. Bothcopy()andconfig()can includePathobjects, so a failed command raisesTypeErrorwhile constructing the message. This particularly defeatscopy(check=False), where missing artifacts are expected to produce a warning. Convert each element when formatting, such as' '.join(str(part) for part in cmd).
Minor fixes needed. Posted 1 actionable finding inline.
The full PR diff was reviewed; some supplemental surrounding file context was omitted.
Automated review; human maintainers own approval decisions.
| """ | ||
| returncode = subprocess.run(cmd, check=False, cwd=self.context_dir, env=self.environ).returncode | ||
| if returncode != 0: | ||
| message = f"Failed to {action} (exit code {returncode}). Command: {' '.join(cmd)}" |
There was a problem hiding this comment.
🟡 Warning · Implementation — Failure message joins non-string command parts
' '.join(cmd) requires every element to be str, but copy() appends host_path (a Path) and config() appends output_yaml (a Path). On a non-zero exit these paths raise TypeError instead of emitting the intended warning or RuntimeError. This is most damaging in copy(), where a missing artifact directory returns non-zero and is explicitly meant to be tolerated via check=False. Format with ' '.join(str(part) for part in cmd).
Greptile SummaryThe PR improves the kit-less container by shipping OVPhysX and all Newton visualizers, adds the required XRender runtime library, surfaces failed Docker commands, and normalizes missing checkpoint-log errors.
Confidence Score: 5/5The PR appears safe to merge based on the reviewed changed paths, with no concrete actionable defect established. The container command wrapper consistently propagates required Docker failures, optional artifact copying remains explicitly non-fatal, the checkpoint error translation matches the documented contract, and the expanded kit-less dependencies are validated during image construction. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
CLI[container.py operation] --> Helper[_run_docker_command]
Helper --> Docker[Docker Compose or docker cp]
Docker -->|exit 0| Success[Continue and report success]
Docker -->|nonzero, required| Error[Raise RuntimeError]
Docker -->|nonzero, optional artifact| Warning[Warn and continue]
Build[Kit-less image build] --> Install[Install Newton, RL, OV, and visualizer extras]
Install --> Assert[Assert OVPhysX, OVRTX, Viser, and Rerun packages]
Assert --> Runtime[Kit-less runtime image]
Reviews (1): Last reviewed commit: "Merge branch 'develop' into jichuanh/kit..." | Re-trigger Greptile |
1. Summary
container.pyno longer reports success on a failed Docker command — it exited0after printingFinished building, which is why 6569864 arrived as a screenshot with no error text.physics=ovphysxand--viz newton,viser,rerunnow work out of the box. Image 14.3 GB → 15.4 GB (+7.7%).libxrender1added:--viz newtoncrashed withAttributeError: 'NoneType' object has no attribute 'XRenderFindVisualFormat'.2. Why OVPhysX was excluded, and why it no longer needs to be
ovphysxcapspackaging<24;ray(viarl[all]) needs>=24.2. Installing OVPhysX downgradedpackagingto 23.2 and brokeray— a real conflict, so the exclusion was correct.The cap is over-strict: ovphysx's entire use of the library is one
from packaging.version import Versioninovphysx/api.py. Apackaging>=26.0override reconciles it, as the neighbouring overrides already do for other over-strict pins. The in-file comment claimed an OmniClient pin instead;omniclientappears nowhere inuv.lock.3. Validation
Run against the rebuilt image with QA's verbatim commands:
train … physics=ovphysx renderer=ovrtxTraining time: 155.44 splay …, empty log dirValueError: No runs present in the directory(was a bareFileNotFoundError)play … --viz newton,viser,rerun:8080, rerun:9090serving1, noFinished building(was exit0)Newton regression:
presets=newton_mjwarp→Training time: 2.06 s. Build gated by in-image assertions onovphysx,ovrtx,viser,rerun-sdk.4. Notes
docker.sockpermission error, not an Isaac Lab defect — but it surfaced the silent-success bug fixed here.uv pip checknow reports ovphysx's declaredpackaging<24as violated. That is inherent to any override; no CI job runsuv pip check.Dockerfile.*hard-codesuseradd --uid 1000, which breaks bind-mounted source reads on hosts with a different uid and leaves the X cookie unreadable. Separate change.5. Type of change
6. Checklist
pre-commitchecks with./isaaclab.sh --format