From 8561e9d5ba1bacaf912a8a43ee4c6d521a8d7fbf Mon Sep 17 00:00:00 2001 From: James L Date: Sun, 22 Feb 2026 21:19:59 -0500 Subject: [PATCH] Fix esptool discovery: prefer pip-installed over bundled Bundled esptool.py runs via sys.executable, which may be a Python that lacks pyserial (e.g. miniconda). Reorder find_esptool() to prefer pip-installed esptool first (handles its own deps), and only fall back to bundled/PlatformIO scripts if pyserial is importable. Give a clear error message if neither works. --- flash.py | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/flash.py b/flash.py index 76cc1e9..6a5108e 100644 --- a/flash.py +++ b/flash.py @@ -60,25 +60,44 @@ BOOT_APP0_BIN = os.path.expanduser( # ── Helpers ──────────────────────────────────────────────────────────────────── def find_esptool(): - """Find esptool.py — bundled, pip-installed, or PlatformIO's copy.""" - # 1. Bundled in Release/ - bundled = os.path.join(os.path.dirname(__file__), "Release", "esptool", "esptool.py") - if os.path.isfile(bundled): - return [sys.executable, bundled] + """Find esptool.py — pip-installed, bundled, or PlatformIO's copy. - # 2. pip-installed esptool + Prefer pip-installed esptool first (handles its own deps), then fall + back to the bundled script — but only if pyserial is importable in + the current Python interpreter. + """ + # 1. pip-installed esptool (standalone executable, no dep issues) if shutil.which("esptool.py"): return ["esptool.py"] if shutil.which("esptool"): return ["esptool"] + # Check if pyserial is available before using script-based esptool + try: + import serial # noqa: F401 + has_pyserial = True + except ImportError: + has_pyserial = False + + # 2. Bundled in Release/ + bundled = os.path.join(os.path.dirname(__file__), "Release", "esptool", "esptool.py") + if os.path.isfile(bundled) and has_pyserial: + return [sys.executable, bundled] + # 3. PlatformIO's esptool pio_esptool = os.path.expanduser( "~/.platformio/packages/tool-esptoolpy/esptool.py" ) - if os.path.isfile(pio_esptool): + if os.path.isfile(pio_esptool) and has_pyserial: return [sys.executable, pio_esptool] + # 4. Bundled exists but pyserial is missing — tell the user + if os.path.isfile(bundled) and not has_pyserial: + print("Found bundled esptool but pyserial is not installed.") + print("Install it with: pip install pyserial") + print("Or install the standalone esptool: pip install esptool") + sys.exit(1) + return None