Skip to content

Commit e17ef18

Browse files
authored
use uv as package manager for resolving python lib dependencies (#212)
1 parent e554b70 commit e17ef18

File tree

4 files changed

+199
-171
lines changed

4 files changed

+199
-171
lines changed

builder/frameworks/arduino.py

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
http://arduino.cc/en/Reference/HomePage
2323
"""
2424

25-
import subprocess
26-
import json
2725
import os
2826
import sys
2927
import shutil
@@ -34,23 +32,12 @@
3432
from pathlib import Path
3533
from typing import Union, List
3634

37-
import semantic_version
3835
from SCons.Script import DefaultEnvironment, SConscript
3936
from platformio import fs
40-
from platformio.package.version import pepver_to_semver
4137
from platformio.package.manager.tool import ToolPackageManager
4238

4339
IS_WINDOWS = sys.platform.startswith("win")
4440

45-
python_deps = {
46-
"wheel": ">=0.35.1",
47-
"rich-click": ">=1.8.6",
48-
"PyYAML": ">=6.0.2",
49-
"intelhex": ">=2.3.0",
50-
"rich": ">=14.0.0",
51-
"esp-idf-size": ">=1.6.1"
52-
}
53-
5441
# Constants for better performance
5542
UNICORE_FLAGS = {
5643
"CORE32SOLO1",
@@ -601,53 +588,6 @@ def has_unicore_flags():
601588
env.Replace(BUILD_UNFLAGS=new_build_unflags)
602589

603590

604-
def get_packages_to_install(deps, installed_packages):
605-
"""Generator for packages to install"""
606-
for package, spec in deps.items():
607-
if package not in installed_packages:
608-
yield package
609-
else:
610-
version_spec = semantic_version.Spec(spec)
611-
if not version_spec.match(installed_packages[package]):
612-
yield package
613-
614-
615-
def install_python_deps():
616-
def _get_installed_pip_packages():
617-
result = {}
618-
try:
619-
pip_output = subprocess.check_output([
620-
env.subst("$PYTHONEXE"),
621-
"-m", "pip", "list", "--format=json",
622-
"--disable-pip-version-check"
623-
])
624-
packages = json.loads(pip_output)
625-
for p in packages:
626-
result[p["name"]] = pepver_to_semver(p["version"])
627-
except Exception:
628-
print("Warning! Couldn't extract the list of installed Python "
629-
"packages.")
630-
631-
return result
632-
633-
installed_packages = _get_installed_pip_packages()
634-
packages_to_install = list(get_packages_to_install(python_deps,
635-
installed_packages))
636-
637-
if packages_to_install:
638-
packages_str = " ".join(f'"{p}{python_deps[p]}"'
639-
for p in packages_to_install)
640-
env.Execute(
641-
env.VerboseAction(
642-
f'"$PYTHONEXE" -m pip install -U -q -q -q {packages_str}',
643-
"Installing Arduino Python dependencies",
644-
)
645-
)
646-
647-
648-
install_python_deps()
649-
650-
651591
def get_MD5_hash(phrase):
652592
return hashlib.md5(phrase.encode('utf-8')).hexdigest()[:16]
653593

@@ -955,6 +895,7 @@ def get_frameworks_in_current_env():
955895

956896
if ("arduino" in pioframework and "espidf" not in pioframework and
957897
arduino_lib_compile_flag in ("Inactive", "True")):
898+
958899
# try to remove not needed include path if an lib_ignore entry exists
959900
from component_manager import ComponentManager
960901
component_manager = ComponentManager(env)
@@ -965,8 +906,6 @@ def get_frameworks_in_current_env():
965906
env.AddPostAction("checkprogsize", silent_action)
966907

967908
if IS_WINDOWS:
968-
# Smart include path optimization based on bleeding edge configurable
969-
# threshold
970909
env.AddBuildMiddleware(smart_include_length_shorten)
971910

972911
build_script_path = join(FRAMEWORK_DIR, "tools", "pioarduino-build.py")

builder/frameworks/espidf.py

Lines changed: 19 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -56,68 +56,6 @@
5656
if os.path.exists(map_file):
5757
os.remove(map_file)
5858

59-
def install_standard_python_deps():
60-
def _get_installed_standard_pip_packages():
61-
result = {}
62-
packages = {}
63-
pip_output = subprocess.check_output(
64-
[
65-
env.subst("$PYTHONEXE"),
66-
"-m",
67-
"pip",
68-
"list",
69-
"--format=json",
70-
"--disable-pip-version-check",
71-
]
72-
)
73-
try:
74-
packages = json.loads(pip_output)
75-
except:
76-
print("Warning! Couldn't extract the list of installed Python packages.")
77-
return {}
78-
for p in packages:
79-
result[p["name"]] = pepver_to_semver(p["version"])
80-
81-
return result
82-
83-
deps = {
84-
"wheel": ">=0.35.1",
85-
"rich-click": ">=1.8.6",
86-
"PyYAML": ">=6.0.2",
87-
"intelhex": ">=2.3.0",
88-
"rich": ">=14.0.0",
89-
"esp-idf-size": ">=1.6.1"
90-
}
91-
92-
installed_packages = _get_installed_standard_pip_packages()
93-
packages_to_install = []
94-
for package, spec in deps.items():
95-
if package not in installed_packages:
96-
packages_to_install.append(package)
97-
else:
98-
version_spec = semantic_version.Spec(spec)
99-
if not version_spec.match(installed_packages[package]):
100-
packages_to_install.append(package)
101-
102-
if packages_to_install:
103-
env.Execute(
104-
env.VerboseAction(
105-
(
106-
'"$PYTHONEXE" -m pip install -U -q -q -q '
107-
+ " ".join(
108-
[
109-
'"%s%s"' % (p, deps[p])
110-
for p in packages_to_install
111-
]
112-
)
113-
),
114-
"Installing standard Python dependencies",
115-
)
116-
)
117-
return
118-
119-
install_standard_python_deps()
120-
12159
# Allow changes in folders of managed components
12260
os.environ["IDF_COMPONENT_OVERWRITE_MANAGED_COMPONENTS"] = "1"
12361

@@ -173,7 +111,7 @@ def create_silent_action(action_func):
173111
os.rename(ARDUINO_FRAMEWORK_DIR, new_path)
174112
ARDUINO_FRAMEWORK_DIR = new_path
175113
assert ARDUINO_FRAMEWORK_DIR and os.path.isdir(ARDUINO_FRAMEWORK_DIR)
176-
arduino_libs_mcu = join(platform.get_package_dir("framework-arduinoespressif32-libs"),mcu)
114+
arduino_libs_mcu = join(platform.get_package_dir("framework-arduinoespressif32-libs"), mcu)
177115

178116
BUILD_DIR = env.subst("$BUILD_DIR")
179117
PROJECT_DIR = env.subst("$PROJECT_DIR")
@@ -1548,24 +1486,17 @@ def generate_mbedtls_bundle(sdk_config):
15481486

15491487

15501488
def install_python_deps():
1551-
def _get_installed_pip_packages(python_exe_path):
1489+
def _get_installed_uv_packages(python_exe_path):
15521490
result = {}
1553-
packages = {}
1554-
pip_output = subprocess.check_output(
1555-
[
1556-
python_exe_path,
1557-
"-m",
1558-
"pip",
1559-
"list",
1560-
"--format=json",
1561-
"--disable-pip-version-check",
1562-
]
1563-
)
15641491
try:
1565-
packages = json.loads(pip_output)
1566-
except:
1567-
print("Warning! Couldn't extract the list of installed Python packages.")
1492+
uv_output = subprocess.check_output([
1493+
"uv", "pip", "list", "--python", python_exe_path, "--format=json"
1494+
])
1495+
packages = json.loads(uv_output)
1496+
except (subprocess.CalledProcessError, json.JSONDecodeError, OSError) as e:
1497+
print(f"Warning! Couldn't extract the list of installed Python packages: {e}")
15681498
return {}
1499+
15691500
for p in packages:
15701501
result[p["name"]] = pepver_to_semver(p["version"])
15711502

@@ -1576,7 +1507,7 @@ def _get_installed_pip_packages(python_exe_path):
15761507
return
15771508

15781509
deps = {
1579-
"wheel": ">=0.35.1",
1510+
"uv": ">=0.1.0",
15801511
# https://github.com/platformio/platformio-core/issues/4614
15811512
"urllib3": "<2",
15821513
# https://github.com/platformio/platform-espressif32/issues/635
@@ -1590,7 +1521,7 @@ def _get_installed_pip_packages(python_exe_path):
15901521
deps["chardet"] = ">=3.0.2,<4"
15911522

15921523
python_exe_path = get_python_exe()
1593-
installed_packages = _get_installed_pip_packages(python_exe_path)
1524+
installed_packages = _get_installed_uv_packages(python_exe_path)
15941525
packages_to_install = []
15951526
for package, spec in deps.items():
15961527
if package not in installed_packages:
@@ -1601,21 +1532,22 @@ def _get_installed_pip_packages(python_exe_path):
16011532
packages_to_install.append(package)
16021533

16031534
if packages_to_install:
1535+
packages_str = " ".join(['"%s%s"' % (p, deps[p]) for p in packages_to_install])
1536+
1537+
# Use uv to install packages in the specific Python environment
16041538
env.Execute(
16051539
env.VerboseAction(
1606-
(
1607-
'"%s" -m pip install -U -q -q -q ' % python_exe_path
1608-
+ " ".join(['"%s%s"' % (p, deps[p]) for p in packages_to_install])
1609-
),
1610-
"Installing ESP-IDF's Python dependencies",
1540+
f'uv pip install --python "{python_exe_path}" {packages_str}',
1541+
"Installing ESP-IDF's Python dependencies with uv",
16111542
)
16121543
)
16131544

16141545
if IS_WINDOWS and "windows-curses" not in installed_packages:
1546+
# Install windows-curses in the IDF Python environment
16151547
env.Execute(
16161548
env.VerboseAction(
1617-
'"%s" -m pip install -q -q -q windows-curses' % python_exe_path,
1618-
"Installing windows-curses package",
1549+
f'uv pip install --python "{python_exe_path}" windows-curses',
1550+
"Installing windows-curses package with uv",
16191551
)
16201552
)
16211553

0 commit comments

Comments
 (0)