1616pytestmark = pytest .mark .unit
1717
1818
19- def _repo_root () -> Path :
20- """Find the Isaac Lab repository root from this test file."""
21- for parent in Path (__file__ ).resolve ().parents :
22- if (parent / "pyproject.toml" ).is_file () and (parent / "source" ).is_dir ():
23- return parent
24- raise RuntimeError ("Could not find Isaac Lab repository root." )
25-
26-
27- def _root_pyproject () -> dict :
19+ def _root_pyproject (source_checkout_root : Path ) -> dict :
2820 """Load the root development ``pyproject.toml``."""
29- with (_repo_root () / "pyproject.toml" ).open ("rb" ) as f :
21+ with (source_checkout_root / "pyproject.toml" ).open ("rb" ) as f :
3022 return tomllib .load (f )
3123
3224
33- def test_uv_run_extra_names_match_documented_workflow ():
25+ def test_uv_run_extra_names_match_documented_workflow (source_checkout_root : Path ):
3426 """Docs must only reference ``uv run --extra`` names that pyproject defines."""
35- repo_root = _repo_root ()
27+ repo_root = source_checkout_root
3628 docs = (repo_root / "docs/source/setup/installation/index.rst" ).read_text (encoding = "utf-8" )
3729 documented_extras = set (re .findall (r"--extra\s+([A-Za-z0-9_-]+)" , docs ))
38- optional_dependencies = _root_pyproject ()["project" ]["optional-dependencies" ]
30+ optional_dependencies = _root_pyproject (source_checkout_root )["project" ]["optional-dependencies" ]
3931
4032 assert documented_extras
4133 assert documented_extras <= set (optional_dependencies )
4234
4335
44- def test_uv_run_exposes_centralized_feature_extras ():
36+ def test_uv_run_exposes_centralized_feature_extras (source_checkout_root : Path ):
4537 """The root project centralizes optional third-party deps into named extras."""
46- optional_dependencies = _root_pyproject ()["project" ]["optional-dependencies" ]
38+ optional_dependencies = _root_pyproject (source_checkout_root )["project" ]["optional-dependencies" ]
4739
4840 # Feature extras a user can activate with ``uv run --extra``.
4941 expected_extras = {
@@ -84,9 +76,9 @@ def test_uv_run_exposes_centralized_feature_extras():
8476 assert any (dep .startswith ("ovstage" ) for dep in optional_dependencies ["ovrtx" ])
8577
8678
87- def test_all_extra_aggregates_curated_ov_rl_and_visualizer_extras ():
79+ def test_all_extra_aggregates_curated_ov_rl_and_visualizer_extras (source_checkout_root : Path ):
8880 """``all`` aggregates only the curated OV, RL, and visualizer extras."""
89- optional = _root_pyproject ()["project" ]["optional-dependencies" ]
81+ optional = _root_pyproject (source_checkout_root )["project" ]["optional-dependencies" ]
9082
9183 assert len (optional ["all" ]) == 1
9284 aggregated = set (re .fullmatch (r"isaaclab-dev\[(.+)\]" , optional ["all" ][0 ]).group (1 ).split ("," ))
@@ -108,9 +100,9 @@ def test_all_extra_aggregates_curated_ov_rl_and_visualizer_extras():
108100 }
109101
110102
111- def test_tetrahedralization_is_explicit_extra_only ():
103+ def test_tetrahedralization_is_explicit_extra_only (source_checkout_root : Path ):
112104 """TetWild and its visualization stack are installed only when requested."""
113- project = _root_pyproject ()["project" ]
105+ project = _root_pyproject (source_checkout_root )["project" ]
114106 optional = project ["optional-dependencies" ]
115107
116108 assert not any (dep .startswith ("pytetwild" ) for dep in project ["dependencies" ])
@@ -122,14 +114,14 @@ def test_tetrahedralization_is_explicit_extra_only():
122114 assert not any ("tetrahedralization" in dep or dep .startswith ("pytetwild" ) for dep in deps )
123115
124116
125- def test_version_single_source_matches_literal_pins ():
117+ def test_version_single_source_matches_literal_pins (source_checkout_root : Path ):
126118 """``[tool.isaaclab.versions]`` is the single source for externally-pinned versions.
127119
128120 TOML cannot interpolate, so the literal pins in ``[project.dependencies]``,
129121 ``[project.optional-dependencies]``, and ``[tool.uv].override-dependencies`` must
130122 mirror the table exactly. This test fails if any of them drift apart.
131123 """
132- pyproject = _root_pyproject ()
124+ pyproject = _root_pyproject (source_checkout_root )
133125 versions = pyproject ["tool" ]["isaaclab" ]["versions" ]
134126 dependencies = pyproject ["project" ]["dependencies" ]
135127 optional = pyproject ["project" ]["optional-dependencies" ]
@@ -156,7 +148,7 @@ def spec(package: str) -> str:
156148 # ovrtx`` ignores this ceiling). Each such install must therefore be pinned:
157149 # either by carrying the literal range, or by referencing the ``resolve-ov-pins``
158150 # action output, which reads the pin from this same table. Never a bare ``ovrtx``.
159- build_workflow = (_repo_root () / ".github/workflows/build.yaml" ).read_text (encoding = "utf-8" )
151+ build_workflow = (source_checkout_root / ".github/workflows/build.yaml" ).read_text (encoding = "utf-8" )
160152 assert "ovphysx==0.4.13" not in build_workflow
161153 ovrtx_install_lines = [
162154 line .strip () for line in build_workflow .splitlines () if "extra-pip-packages:" in line and "ovrtx" in line
@@ -179,9 +171,9 @@ def spec(package: str) -> str:
179171 assert warp_spec in dependencies
180172
181173
182- def test_public_ov_packages_use_public_pypi_index ():
174+ def test_public_ov_packages_use_public_pypi_index (source_checkout_root : Path ):
183175 """Public OV packages must not resolve from the NVIDIA package index."""
184- pyproject = _root_pyproject ()
176+ pyproject = _root_pyproject (source_checkout_root )
185177 indexes = {index .get ("name" ): index for index in pyproject ["tool" ]["uv" ]["index" ]}
186178 sources = pyproject ["tool" ]["uv" ]["sources" ]
187179
@@ -194,7 +186,7 @@ def test_public_ov_packages_use_public_pypi_index():
194186 assert sources [package ] == {"index" : "pypi-public" }
195187
196188
197- def test_uv_run_declares_no_extra_conflicts ():
189+ def test_uv_run_declares_no_extra_conflicts (source_checkout_root : Path ):
198190 """No extra is forked: every combination resolves into a single environment.
199191
200192 ``[tool.uv].conflicts`` used to fork ``isaacsim`` / ``teleop`` away from the OV runtimes,
@@ -203,21 +195,21 @@ def test_uv_run_declares_no_extra_conflicts():
203195 importers install beside Isaac Sim without displacing it: the two distributions share no
204196 files, and Kit serves ``isaacsim.asset`` from its extension roots either way.
205197 """
206- tool_uv = _root_pyproject ()["tool" ]["uv" ]
198+ tool_uv = _root_pyproject (source_checkout_root )["tool" ]["uv" ]
207199
208200 assert "conflicts" not in tool_uv
209201 for override in ("packaging>=20,<27" , "websockets>=14.0,<17.0.0" , "coverage>=7.6.1" ):
210202 assert override in tool_uv ["override-dependencies" ]
211203
212204
213- def test_uv_run_isaacsim_is_an_opt_in_extra ():
205+ def test_uv_run_isaacsim_is_an_opt_in_extra (source_checkout_root : Path ):
214206 """Isaac Sim is never a base dependency, but it is a real workspace extra.
215207
216208 PhysX/Isaac Sim must stay out of ``[project.dependencies]`` so the bare ``uv run``
217209 keeps working without Kit, while still being an ``optional-dependencies`` entry so
218210 ``uv run --extra isaacsim`` resolves.
219211 """
220- pyproject = _root_pyproject ()
212+ pyproject = _root_pyproject (source_checkout_root )
221213 project = pyproject ["project" ]
222214 base_dependency_names = {re .split (r"[\s<>=!~\[;]" , dep , maxsplit = 1 )[0 ] for dep in project ["dependencies" ]}
223215
@@ -230,14 +222,14 @@ def test_uv_run_isaacsim_is_an_opt_in_extra():
230222 assert "wheel-extras" not in pyproject .get ("tool" , {}).get ("isaaclab" , {})
231223
232224
233- def test_uv_run_teleop_extra_excludes_isaacsim ():
225+ def test_uv_run_teleop_extra_excludes_isaacsim (source_checkout_root : Path ):
234226 """``teleop`` carries the teleop stack only; Isaac Sim stays its own extra.
235227
236228 XR teleop needs the Kit XR runtime, but environments that already provide Kit (the
237229 container images) must not install a second copy of it. Users who need the wheel run
238230 ``--extra teleop,isaacsim``.
239231 """
240- optional_dependencies = _root_pyproject ()["project" ]["optional-dependencies" ]
232+ optional_dependencies = _root_pyproject (source_checkout_root )["project" ]["optional-dependencies" ]
241233 teleop = optional_dependencies ["teleop" ]
242234
243235 assert not any (dep .startswith ("isaacsim" ) for dep in teleop )
@@ -247,18 +239,18 @@ def test_uv_run_teleop_extra_excludes_isaacsim():
247239 assert not any (dep .startswith ("robomimic" ) for dep in teleop )
248240
249241
250- def test_uv_run_base_dependencies_cover_newton_rsl_rl_training ():
242+ def test_uv_run_base_dependencies_cover_newton_rsl_rl_training (source_checkout_root : Path ):
251243 """The documented bare ``uv run isaaclab train`` command needs Newton and RSL-RL in core."""
252- dependencies = _root_pyproject ()["project" ]["dependencies" ]
244+ dependencies = _root_pyproject (source_checkout_root )["project" ]["dependencies" ]
253245
254246 # Newton is the default physics engine and RSL-RL the default training library,
255247 # so both ship as core third-party requirements (not opt-in extras).
256248 assert any (dep .startswith ("newton[sim]" ) for dep in dependencies )
257249 assert any (dep .startswith ("rsl-rl-lib" ) for dep in dependencies )
258250
259251
260- def test_uv_run_uses_managed_python ():
252+ def test_uv_run_uses_managed_python (source_checkout_root : Path ):
261253 """Avoid building the project venv from conda Python and its older C++ runtime."""
262- tool_uv = _root_pyproject ()["tool" ]["uv" ]
254+ tool_uv = _root_pyproject (source_checkout_root )["tool" ]["uv" ]
263255
264256 assert tool_uv ["python-preference" ] == "only-managed"
0 commit comments