mirror of
https://github.com/esphome/esphome.git
synced 2026-10-03 09:46:03 +00:00
[core] Use uv for the ESP-IDF Python environment when available (#18838)
This commit is contained in:
@@ -1053,15 +1053,28 @@ def _check_esp_idf_python_env_install(
|
||||
constraint_file_path,
|
||||
)
|
||||
|
||||
cmd_pip_install = [
|
||||
str(env_python_path),
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
"--upgrade",
|
||||
"--constraint",
|
||||
constraint_file_path,
|
||||
]
|
||||
# uv (much faster than pip) when available, e.g. in the docker image
|
||||
if uv_path := shutil.which("uv"):
|
||||
cmd_pip_install = [
|
||||
uv_path,
|
||||
"pip",
|
||||
"install",
|
||||
"--python",
|
||||
str(env_python_path),
|
||||
"--upgrade",
|
||||
"--constraint",
|
||||
str(constraint_file_path),
|
||||
]
|
||||
else:
|
||||
cmd_pip_install = [
|
||||
str(env_python_path),
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
"--upgrade",
|
||||
"--constraint",
|
||||
str(constraint_file_path),
|
||||
]
|
||||
|
||||
_LOGGER.info("Installing ESP-IDF %s Python dependencies ...", version)
|
||||
cmd = cmd_pip_install + [
|
||||
@@ -1135,6 +1148,8 @@ def check_esp_idf_install(
|
||||
env = {}
|
||||
env["IDF_TOOLS_PATH"] = str(get_idf_tools_path())
|
||||
env["IDF_PATH"] = ""
|
||||
# uv defaults to 3 HTTP retries; match the pioarduino penv's bump to 10
|
||||
env["UV_HTTP_RETRIES"] = os.environ.get("UV_HTTP_RETRIES", "10")
|
||||
|
||||
# An explicit ESPHOME_IDF_DEFAULT_TARGETS wins over the caller's
|
||||
# per-variant request (builder-image pre-warm); otherwise the caller's
|
||||
|
||||
@@ -520,6 +520,33 @@ def test_check_esp_idf_install_feature_failure(espidf_mocks: SimpleNamespace) ->
|
||||
check_esp_idf_install(_IDF_VERSION, force=True, features=["fb"])
|
||||
|
||||
|
||||
def test_python_deps_use_uv_when_available(
|
||||
espidf_mocks: SimpleNamespace, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""The python env installs go through uv when on the PATH, pip otherwise."""
|
||||
monkeypatch.delenv("UV_HTTP_RETRIES", raising=False)
|
||||
with patch(
|
||||
"esphome.espidf.framework.shutil.which",
|
||||
# Keyed on the name: the same which() also probes the default tools
|
||||
side_effect=lambda name: "/usr/bin/uv" if name == "uv" else None,
|
||||
):
|
||||
check_esp_idf_install(_IDF_VERSION, force=True, features=["fb"])
|
||||
upgrade_call, feature_call = espidf_mocks.run_ok.call_args_list[1:3]
|
||||
upgrade_cmd, feature_cmd = upgrade_call.args[0], feature_call.args[0]
|
||||
assert upgrade_cmd[:3] == ["/usr/bin/uv", "pip", "install"]
|
||||
assert "--python" in upgrade_cmd
|
||||
assert feature_cmd[:3] == ["/usr/bin/uv", "pip", "install"]
|
||||
assert upgrade_call.kwargs["env"]["UV_HTTP_RETRIES"] == "10"
|
||||
|
||||
espidf_mocks.run_ok.reset_mock()
|
||||
monkeypatch.setenv("UV_HTTP_RETRIES", "3") # an explicit user value wins
|
||||
with patch("esphome.espidf.framework.shutil.which", return_value=None):
|
||||
check_esp_idf_install(_IDF_VERSION, force=True, features=["fb"])
|
||||
upgrade_call = espidf_mocks.run_ok.call_args_list[1]
|
||||
assert upgrade_call.args[0][1:4] == ["-m", "pip", "install"]
|
||||
assert upgrade_call.kwargs["env"]["UV_HTTP_RETRIES"] == "3"
|
||||
|
||||
|
||||
def _mark_installed() -> None:
|
||||
"""Create the extracted marker and python-env interpreter so the install
|
||||
check takes the already-installed path rather than force-installing."""
|
||||
|
||||
Reference in New Issue
Block a user