Skip to content

Commit 3247b8a

Browse files
committed
[RELEASE ONLY CHANGES] Preserve source-pinned torch in CI installs
Respect --use-pt-pinned-commit when generating the installed wheel metadata so pip keeps the torch build used to link our extensions. Ordinary release wheel metadata remains pinned to torch 2.15.0. Assisted by Codex.
1 parent bb943fa commit 3247b8a

3 files changed

Lines changed: 89 additions & 2 deletions

File tree

‎.ci/scripts/tests/test_cu134_dependencies.py‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
# LICENSE file in the root directory of this source tree.
66

77
import ast
8+
import importlib.metadata
89
import importlib.util
910
import os
11+
import re
1012
import subprocess
1113
import sys
1214
import unittest
1315
from pathlib import Path
16+
from typing import List
1417
from unittest.mock import patch
1518

1619
from packaging.requirements import Requirement
@@ -270,6 +273,80 @@ def test_package_install_preserves_source_pinned_torchao(self):
270273
self.assertIn("torch", core)
271274
self.assertFalse(any(arg.startswith("torch==") for arg in core))
272275

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+
273350
def test_cu134_keeps_explicit_torchao_source_build(self):
274351
with patch.dict(sys.modules, {"install_requirements": self.installer}):
275352
package_installer = load_module("install_executorch")

‎install_executorch.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,11 @@ def main(args):
251251
)
252252
if args.verbose:
253253
cmd.append("-v")
254-
subprocess.run(cmd, check=True)
254+
package_env = os.environ.copy()
255+
package_env["_EXECUTORCH_USE_PT_PINNED_COMMIT"] = (
256+
"1" if args.use_pt_pinned_commit else "0"
257+
)
258+
subprocess.run(cmd, check=True, env=package_env)
255259

256260
# Step 3: Extra (optional) packages that is only useful for running examples.
257261
if not args.minimal:

‎setup.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353

5454
# Import this before distutils so that setuptools can intercept the distuils
5555
# imports.
56+
import importlib.metadata
5657
import importlib.util
5758
import logging
5859
import os
@@ -1141,6 +1142,11 @@ def _base_dependencies() -> List[str]:
11411142
dynamic) so the minimal build can ship a slimmer set. Keep in sync with the
11421143
project's runtime needs.
11431144
"""
1145+
torch_requirement = "torch==2.15.0"
1146+
if os.environ.get("_EXECUTORCH_USE_PT_PINNED_COMMIT") == "1":
1147+
# CI source builds carry an a0+git version even at the release tag.
1148+
# Preserve the build that our extension libraries link against.
1149+
torch_requirement = f"torch=={importlib.metadata.version('torch')}"
11441150
return [
11451151
"expecttest",
11461152
"flatbuffers",
@@ -1158,7 +1164,7 @@ def _base_dependencies() -> List[str]:
11581164
"py-cpuinfo",
11591165
"requests",
11601166
"pytorch-tokenizers",
1161-
"torch==2.15.0",
1167+
torch_requirement,
11621168
# Shipped code imports torchao at module scope in many places, so a plain install cannot
11631169
# lower a model without it. Among others: the XNNPACK utilities the partitioner uses
11641170
# (backends/xnnpack/utils/utils.py), the Core ML quantizer, and executorch.export itself.

0 commit comments

Comments
 (0)