|
5 | 5 | # LICENSE file in the root directory of this source tree. |
6 | 6 |
|
7 | 7 | import ast |
| 8 | +import importlib.metadata |
8 | 9 | import importlib.util |
9 | 10 | import os |
| 11 | +import re |
10 | 12 | import subprocess |
11 | 13 | import sys |
12 | 14 | import unittest |
13 | 15 | from pathlib import Path |
| 16 | +from typing import List |
14 | 17 | from unittest.mock import patch |
15 | 18 |
|
16 | 19 | from packaging.requirements import Requirement |
@@ -270,6 +273,80 @@ def test_package_install_preserves_source_pinned_torchao(self): |
270 | 273 | self.assertIn("torch", core) |
271 | 274 | self.assertFalse(any(arg.startswith("torch==") for arg in core)) |
272 | 275 |
|
| 276 | + def test_package_metadata_preserves_source_torch_only_when_requested(self): |
| 277 | + with patch.dict(sys.modules, {"install_requirements": self.installer}): |
| 278 | + package_installer = load_module("install_executorch") |
| 279 | + tree = ast.parse((ROOT / "setup.py").read_text()) |
| 280 | + functions = [ |
| 281 | + node |
| 282 | + for node in tree.body |
| 283 | + if isinstance(node, ast.FunctionDef) |
| 284 | + and node.name in {"_base_dependencies", "_minimal_dependencies"} |
| 285 | + ] |
| 286 | + namespace = { |
| 287 | + "List": List, |
| 288 | + "os": os, |
| 289 | + "re": re, |
| 290 | + "importlib": importlib, |
| 291 | + "_torchao_requirement": self.torchao_requirement, |
| 292 | + } |
| 293 | + exec( |
| 294 | + compile(ast.Module(body=functions, type_ignores=[]), "setup.py", "exec"), |
| 295 | + namespace, |
| 296 | + ) |
| 297 | + source_version = "2.15.0a0+git31a77fc" |
| 298 | + for pinned in (False, True): |
| 299 | + with self.subTest(pinned=pinned): |
| 300 | + argv = ["install_executorch", "--minimal"] |
| 301 | + if pinned: |
| 302 | + argv.append("--use-pt-pinned-commit") |
| 303 | + with ( |
| 304 | + patch.dict( |
| 305 | + os.environ, |
| 306 | + {"_EXECUTORCH_USE_PT_PINNED_COMMIT": "1"}, |
| 307 | + clear=True, |
| 308 | + ), |
| 309 | + patch.object(sys, "argv", argv), |
| 310 | + patch.object( |
| 311 | + package_installer, "python_is_compatible", return_value=True |
| 312 | + ), |
| 313 | + patch.object(package_installer, "check_and_update_submodules"), |
| 314 | + patch.object(package_installer, "install_requirements"), |
| 315 | + patch.object(package_installer.subprocess, "run") as run, |
| 316 | + ): |
| 317 | + package_installer.main([]) |
| 318 | + package_env = run.call_args.kwargs["env"] |
| 319 | + self.assertEqual( |
| 320 | + os.environ["_EXECUTORCH_USE_PT_PINNED_COMMIT"], "1" |
| 321 | + ) |
| 322 | + self.assertEqual( |
| 323 | + package_env["_EXECUTORCH_USE_PT_PINNED_COMMIT"], |
| 324 | + "1" if pinned else "0", |
| 325 | + ) |
| 326 | + with ( |
| 327 | + patch.dict(os.environ, package_env, clear=True), |
| 328 | + patch.object( |
| 329 | + importlib.metadata, "version", return_value=source_version |
| 330 | + ), |
| 331 | + ): |
| 332 | + deps = namespace["_base_dependencies"]() |
| 333 | + torch = Requirement( |
| 334 | + next(dep for dep in deps if dep.startswith("torch==")) |
| 335 | + ) |
| 336 | + self.assertEqual(source_version in torch.specifier, pinned) |
| 337 | + self.assertEqual("2.15.0" in torch.specifier, not pinned) |
| 338 | + self.assertEqual( |
| 339 | + f"torchao>={self.installer.TORCHAO_MIN_VERSION}", |
| 340 | + next(dep for dep in deps if dep.startswith("torchao>=")), |
| 341 | + ) |
| 342 | + self.assertIn("pytorch-tokenizers", deps) |
| 343 | + self.assertFalse( |
| 344 | + any( |
| 345 | + dep.startswith("torch") |
| 346 | + for dep in namespace["_minimal_dependencies"]() |
| 347 | + ) |
| 348 | + ) |
| 349 | + |
273 | 350 | def test_cu134_keeps_explicit_torchao_source_build(self): |
274 | 351 | with patch.dict(sys.modules, {"install_requirements": self.installer}): |
275 | 352 | package_installer = load_module("install_executorch") |
|
0 commit comments