Skip to content

Commit fb25363

Browse files
put executorch in the extras_require (#4324)
1 parent 7124e43 commit fb25363

6 files changed

Lines changed: 114 additions & 18 deletions

File tree

.github/scripts/verify-executorch-reference-runner.sh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,14 @@ if ! "${python_executable}" - <<'PY'
207207
import importlib
208208
import importlib.util
209209
210-
missing = [
211-
name
212-
for name in ("yaml", "torch", "torch_tensorrt", "executorch.exir")
213-
if importlib.util.find_spec(name) is None
214-
]
210+
missing = []
211+
for name in ("yaml", "torch", "torch_tensorrt", "executorch.exir"):
212+
try:
213+
spec = importlib.util.find_spec(name)
214+
except ModuleNotFoundError:
215+
spec = None
216+
if spec is None:
217+
missing.append(name)
215218
if missing:
216219
raise SystemExit(
217220
"Missing Python package(s) required to export the .pte and build the runner: "

.github/workflows/executorch-static-linux.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,5 @@ jobs:
9696
export EXECUTORCH_SOURCE_DIR="$(dirname "${executorch_cmake_location%%:*}")"
9797
export EXECUTORCH_ROOT="${EXECUTORCH_SOURCE_DIR}"
9898
# this is to verify the end user's workflow
99-
python -m pip install pyyaml
99+
python -m pip install pyyaml "executorch>=1.3.1"
100100
.github/scripts/verify-executorch-reference-runner.sh

py/torch_tensorrt/_compile.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -767,8 +767,8 @@ def save(
767767
if output_format == "executorch" and not _has_executorch_exir():
768768
raise ImportError(
769769
"Saving in ExecuTorch format requires the executorch package "
770-
"with executorch.exir. Install executorch to use "
771-
"output_format='executorch'."
770+
"with executorch.exir. Install with: pip install "
771+
"\"executorch\" to use output_format='executorch'."
772772
)
773773

774774
def _all_are_input_objects(obj: Any) -> bool:
@@ -1314,8 +1314,8 @@ def _save_as_executorch(exp_program: Any, file_path: str, **kwargs: Any) -> None
13141314
from executorch.exir import to_edge_transform_and_lower
13151315
except ImportError:
13161316
raise ImportError(
1317-
"ExecuTorch is not installed. Please install it to use output_format='executorch'. "
1318-
"See https://pytorch.org/executorch/stable/getting-started-setup.html"
1317+
"ExecuTorch is not installed. Install with: pip install "
1318+
"\"executorch\" to use output_format='executorch'."
13191319
)
13201320
import torch_tensorrt.dynamo.runtime.meta_ops.register_meta_ops # noqa: F401
13211321
from torch_tensorrt.executorch import (

py/torch_tensorrt/executorch/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __getattr__(name: str) -> NoReturn:
1818
raise ImportError(
1919
f"Cannot access torch_tensorrt.executorch.{name}: "
2020
"ExecuTorch with executorch.exir is required. "
21-
"Install with: pip install executorch"
21+
'Install with: pip install "executorch"'
2222
)
2323

2424
__all__ = [

setup.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ def load_dep_info():
9999
CI_BUILD = False
100100
USE_TRT_RTX = False
101101

102-
EXECUTORCH_REQUIREMENT = "executorch>=1.2.0"
102+
EXECUTORCH_REQUIREMENT = "executorch>=1.3.1"
103+
EXTRAS_REQUIRE = {
104+
"executorch": [EXECUTORCH_REQUIREMENT],
105+
"all": [EXECUTORCH_REQUIREMENT],
106+
}
103107

104108

105109
if "--use-rtx" in sys.argv:
@@ -608,9 +612,7 @@ def run(self):
608612
)
609613

610614
package_data = {}
611-
executorch_header_package_data = (
612-
[] if IS_DLFW_CI else ["include/torch_tensorrt/executorch/*.h"]
613-
)
615+
executorch_header_package_data = ["include/torch_tensorrt/executorch/*.h"]
614616

615617
if not (PY_ONLY or NO_TS):
616618
tensorrt_x86_64_external_dir = (
@@ -855,7 +857,6 @@ def get_x86_64_requirements(base_requirements):
855857
]
856858
else:
857859
requirements = requirements + [
858-
EXECUTORCH_REQUIREMENT,
859860
"tensorrt>=11.0.0,<11.1.0",
860861
]
861862
cuda_version = torch.version.cuda
@@ -914,6 +915,7 @@ def get_requirements():
914915
},
915916
zip_safe=False,
916917
install_requires=get_requirements(),
918+
extras_require=EXTRAS_REQUIRE,
917919
packages=packages,
918920
package_dir=package_dir,
919921
include_package_data=False,

tests/py/dynamo/executorch/test_api.py

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import ast
12
import importlib
23
import sys
4+
from pathlib import Path
35

46
import pytest
57
import torch
@@ -18,7 +20,7 @@ def fake_find_spec(name, package=None):
1820
monkeypatch.setattr(importlib.util, "find_spec", fake_find_spec)
1921
module = importlib.import_module("torch_tensorrt.executorch")
2022

21-
with pytest.raises(ImportError, match="ExecuTorch.*required"):
23+
with pytest.raises(ImportError, match=r"torch_tensorrt\[executorch\]"):
2224
_ = module.TensorRTBackend
2325

2426
sys.modules.pop("torch_tensorrt.executorch", None)
@@ -39,7 +41,7 @@ def fake_find_spec(name, package=None):
3941

4042
from torch_tensorrt._compile import save
4143

42-
with pytest.raises(ImportError, match="Saving in ExecuTorch format requires"):
44+
with pytest.raises(ImportError, match=r"torch_tensorrt\[executorch\]"):
4345
save(
4446
torch.nn.Linear(1, 1),
4547
str(tmp_path / "model.pte"),
@@ -53,3 +55,92 @@ def test_public_api_symbols_present():
5355
assert "get_edge_compile_config" in module.__all__
5456
assert "TensorRTPartitioner" in module.__all__
5557
assert "TensorRTBackend" in module.__all__
58+
59+
60+
_REPO_ROOT = Path(__file__).resolve().parents[4]
61+
_SETUP_PY = _REPO_ROOT / "setup.py"
62+
63+
64+
def _setup_tree():
65+
return ast.parse(_SETUP_PY.read_text(encoding="utf-8"))
66+
67+
68+
def _assignment_value(tree, name):
69+
for node in tree.body:
70+
if isinstance(node, ast.Assign) and any(
71+
isinstance(target, ast.Name) and target.id == name
72+
for target in node.targets
73+
):
74+
return node.value
75+
raise AssertionError(f"Could not find assignment for {name}")
76+
77+
78+
def _function_def(tree, name):
79+
for node in tree.body:
80+
if isinstance(node, ast.FunctionDef) and node.name == name:
81+
return node
82+
raise AssertionError(f"Could not find function {name}")
83+
84+
85+
@pytest.mark.unit
86+
def test_packaging_declares_executorch_extra():
87+
tree = _setup_tree()
88+
extras = _assignment_value(tree, "EXTRAS_REQUIRE")
89+
assert isinstance(extras, ast.Dict)
90+
91+
extras_by_name = {
92+
key.value: value
93+
for key, value in zip(extras.keys, extras.values)
94+
if isinstance(key, ast.Constant)
95+
}
96+
for extra_name in ("executorch", "all"):
97+
assert extra_name in extras_by_name
98+
requirements = extras_by_name[extra_name]
99+
assert isinstance(requirements, ast.List)
100+
assert any(
101+
isinstance(requirement, ast.Name)
102+
and requirement.id == "EXECUTORCH_REQUIREMENT"
103+
for requirement in requirements.elts
104+
)
105+
106+
setup_call = next(
107+
node
108+
for node in ast.walk(tree)
109+
if isinstance(node, ast.Call)
110+
and isinstance(node.func, ast.Name)
111+
and node.func.id == "setup"
112+
)
113+
extras_keyword = next(
114+
(keyword for keyword in setup_call.keywords if keyword.arg == "extras_require"),
115+
None,
116+
)
117+
assert extras_keyword is not None
118+
assert isinstance(extras_keyword.value, ast.Name)
119+
assert extras_keyword.value.id == "EXTRAS_REQUIRE"
120+
121+
122+
@pytest.mark.unit
123+
def test_executorch_is_not_base_install_requirement():
124+
tree = _setup_tree()
125+
for function_name in (
126+
"get_jetpack_requirements",
127+
"get_sbsa_requirements",
128+
"get_x86_64_requirements",
129+
"get_requirements",
130+
):
131+
function = _function_def(tree, function_name)
132+
assert not any(
133+
isinstance(node, ast.Name) and node.id == "EXECUTORCH_REQUIREMENT"
134+
for node in ast.walk(function)
135+
)
136+
137+
138+
@pytest.mark.unit
139+
def test_executorch_headers_are_not_dlfw_gated():
140+
tree = _setup_tree()
141+
header_package_data = _assignment_value(tree, "executorch_header_package_data")
142+
assert isinstance(header_package_data, ast.List)
143+
assert not any(
144+
isinstance(node, ast.Name) and node.id == "IS_DLFW_CI"
145+
for node in ast.walk(header_package_data)
146+
)

0 commit comments

Comments
 (0)