Skip to content

Commit 0fe94de

Browse files
shoumikhinJacobSzwejbkaclaude
committed
Declare a slim dependency set for the minimal wheel build
The minimal build mode trimmed the packaged files but not the declared dependencies. Because `pyproject.toml` `[project.dependencies]` is static, a normal `pip install` of the minimal wheel still pulled `coremltools`, `scikit-learn`, `pandas`, `hydra-core`, `omegaconf` and the test-only deps (`expecttest`, `hypothesis`, `kgb`, `parameterized`), which is most of the real install size. The CI smoke test only passed because it used `pip install --no-deps`. Make `dependencies` dynamic in `pyproject.toml` and compute `install_requires` in `setup.py` per build mode. The full wheel keeps the existing set; the minimal wheel declares only what `executorch.exir` needs to export a `.pte`: `flatbuffers`, `numpy`, `packaging`, `pyyaml`, `ruamel.yaml`, `sympy`, `tabulate`, `typing-extensions`. `torch` is assumed present, as before. Update `test_minimal_wheel.sh` to drop `--no-deps` so dependency resolution is exercised, and assert the wheel METADATA declares the slim set and none of the heavy deps. Co-authored-by: Jacob Szwejbka <20804483+JacobSzwejbka@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6322992 commit 0fe94de

3 files changed

Lines changed: 123 additions & 33 deletions

File tree

.ci/scripts/test_minimal_wheel.sh

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ WHEEL_FILE="$(find "${REPO_ROOT}/dist" -maxdepth 1 -name 'executorch-*.whl' | he
4040
test -n "${WHEEL_FILE}"
4141

4242
python - "${WHEEL_FILE}" <<'PY'
43+
import re
4344
import sys
4445
import zipfile
4546
@@ -66,27 +67,77 @@ extensions = [
6667
]
6768
if extensions:
6869
raise AssertionError(f"{wheel_file} unexpectedly contains extensions: {extensions}")
70+
71+
# The minimal wheel must declare only the slim runtime dependency set: none of
72+
# the heavy full-wheel deps, and all of the minimal ones.
73+
metadata_name = next(
74+
(name for name in names if name.endswith(".dist-info/METADATA")), None
75+
)
76+
if metadata_name is None:
77+
raise AssertionError(f"{wheel_file} has no METADATA")
78+
with zipfile.ZipFile(wheel_file) as wheel:
79+
metadata_text = wheel.read(metadata_name).decode("utf-8")
80+
81+
82+
def _dist_name(requirement):
83+
name = re.split(r"[ ;\[<>=!~(]", requirement.strip(), maxsplit=1)[0]
84+
return re.sub(r"[-_.]+", "-", name).lower()
85+
86+
87+
declared = {
88+
_dist_name(line.split(":", 1)[1])
89+
for line in metadata_text.splitlines()
90+
if line.startswith("Requires-Dist:")
91+
}
92+
heavy = {
93+
"coremltools",
94+
"scikit-learn",
95+
"pandas",
96+
"hydra-core",
97+
"omegaconf",
98+
"expecttest",
99+
"hypothesis",
100+
"kgb",
101+
"parameterized",
102+
"pytorch-tokenizers",
103+
}
104+
leaked = sorted(declared & heavy)
105+
if leaked:
106+
raise AssertionError(f"{wheel_file} METADATA declares heavy deps: {leaked}")
107+
expected = {
108+
"flatbuffers",
109+
"numpy",
110+
"packaging",
111+
"pyyaml",
112+
"ruamel-yaml",
113+
"sympy",
114+
"tabulate",
115+
"typing-extensions",
116+
}
117+
missing = sorted(expected - declared)
118+
if missing:
119+
raise AssertionError(f"{wheel_file} METADATA missing minimal deps: {missing}")
69120
PY
70121

71122
deactivate
72123

73124
"${PYTHON_EXECUTABLE}" -m venv "${TEST_VENV}"
74125
source "${TEST_VENV}/bin/activate"
75126
python -m pip install --upgrade pip
127+
# torch and torchvision are needed to export a model but are intentionally not
128+
# declared as wheel dependencies (consumers are expected to bring their own).
76129
python -m pip install \
77-
"flatbuffers" \
78-
"numpy>=2.0.0" \
79-
"packaging" \
80-
"pyyaml" \
81-
"ruamel.yaml" \
82-
"sympy" \
83-
"tabulate" \
84130
"torch" \
85131
"torchvision" \
86-
"typing-extensions>=4.10.0" \
87132
--index-url https://download.pytorch.org/whl/cpu \
88133
--extra-index-url https://pypi.org/simple
89-
python -m pip install --no-deps "${WHEEL_FILE}"
134+
# Install the minimal wheel WITHOUT --no-deps so pip resolves its declared
135+
# dependencies: this proves the slim set is correct and resolvable, and that
136+
# none of the heavy full-wheel deps get pulled in.
137+
python -m pip install \
138+
"${WHEEL_FILE}" \
139+
--index-url https://download.pytorch.org/whl/cpu \
140+
--extra-index-url https://pypi.org/simple
90141

91142
python - <<'PY'
92143
from pathlib import Path

pyproject.toml

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ name = "executorch"
1616
dynamic = [
1717
# setup.py will set the version.
1818
'version',
19+
# setup.py sets dependencies, which vary by build mode (the
20+
# EXECUTORCH_BUILD_MINIMAL wheel declares a slimmer runtime set).
21+
'dependencies',
1922
]
2023
description = "On-device AI across mobile, embedded and edge for PyTorch"
2124
readme = "README-wheel.md"
@@ -51,30 +54,11 @@ classifiers = [
5154
]
5255

5356
requires-python = ">=3.10,<3.14"
54-
dependencies=[
55-
"expecttest",
56-
"flatbuffers",
57-
"hypothesis",
58-
"kgb",
59-
"mpmath==1.3.0",
60-
"numpy>=2.0.0; python_version >= '3.10'",
61-
"packaging",
62-
"pandas>=2.2.2; python_version >= '3.10'",
63-
"parameterized",
64-
"pytorch-tokenizers",
65-
"pyyaml",
66-
"ruamel.yaml",
67-
"sympy",
68-
"tabulate",
69-
# See also third-party/TARGETS for buck's typing-extensions version.
70-
"typing-extensions>=4.10.0",
71-
# Keep this version in sync with: ./backends/apple/coreml/scripts/install_requirements.sh
72-
"coremltools==9.0; platform_system == 'Darwin' or platform_system == 'Linux'",
73-
# scikit-learn is used to support palettization in the coreml backend
74-
"scikit-learn==1.7.1",
75-
"hydra-core>=1.3.0",
76-
"omegaconf>=2.3.0",
77-
]
57+
58+
# Runtime dependencies are declared dynamically (see `dynamic` above) and
59+
# computed in setup.py, so the EXECUTORCH_BUILD_MINIMAL wheel can ship a slimmer
60+
# set than the full wheel. See `_base_dependencies()` / `_minimal_dependencies()`
61+
# in setup.py.
7862

7963
[project.optional-dependencies]
8064
cortex_m = [

setup.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,58 @@ def _minimal_packages() -> List[str]:
165165
)
166166

167167

168+
def _base_dependencies() -> List[str]:
169+
"""Runtime dependencies for the full wheel.
170+
171+
Declared here rather than in pyproject.toml (where `dependencies` is marked
172+
dynamic) so the minimal build can ship a slimmer set. Keep in sync with the
173+
project's runtime needs.
174+
"""
175+
return [
176+
"expecttest",
177+
"flatbuffers",
178+
"hypothesis",
179+
"kgb",
180+
"mpmath==1.3.0",
181+
"numpy>=2.0.0; python_version >= '3.10'",
182+
"packaging",
183+
"pandas>=2.2.2; python_version >= '3.10'",
184+
"parameterized",
185+
"pytorch-tokenizers",
186+
"pyyaml",
187+
"ruamel.yaml",
188+
"sympy",
189+
"tabulate",
190+
# See also third-party/TARGETS for buck's typing-extensions version.
191+
"typing-extensions>=4.10.0",
192+
# Keep this version in sync with: ./backends/apple/coreml/scripts/install_requirements.sh
193+
"coremltools==9.0; platform_system == 'Darwin' or platform_system == 'Linux'",
194+
# scikit-learn is used to support palettization in the coreml backend.
195+
"scikit-learn==1.7.1",
196+
"hydra-core>=1.3.0",
197+
"omegaconf>=2.3.0",
198+
]
199+
200+
201+
def _minimal_dependencies() -> List[str]:
202+
"""Runtime dependencies for the minimal (AOT export only) wheel.
203+
204+
Only what executorch.exir needs to lower and serialize a .pte. torch is
205+
intentionally omitted (consumers bring their own). Keep in sync with
206+
.ci/scripts/test_minimal_wheel.sh.
207+
"""
208+
return [
209+
"flatbuffers",
210+
"numpy>=2.0.0; python_version >= '3.10'",
211+
"packaging",
212+
"pyyaml",
213+
"ruamel.yaml",
214+
"sympy",
215+
"tabulate",
216+
"typing-extensions>=4.10.0",
217+
]
218+
219+
168220
class Version:
169221
"""Static strings that describe the version of the pip package."""
170222

@@ -931,6 +983,9 @@ def run(self): # noqa C901
931983
setup_kwargs = {}
932984
if _is_minimal_build():
933985
setup_kwargs["packages"] = _minimal_packages()
986+
setup_kwargs["install_requires"] = _minimal_dependencies()
987+
else:
988+
setup_kwargs["install_requires"] = _base_dependencies()
934989

935990

936991
setup(

0 commit comments

Comments
 (0)