@@ -111,6 +111,67 @@ def setup_python_paths(env):
111
111
setup_python_paths (env )
112
112
113
113
114
+ def _get_executable_path (python_exe , executable_name ):
115
+ """
116
+ Get the path to an executable binary (esptool, uv, etc.) based on the Python executable path.
117
+
118
+ Args:
119
+ python_exe (str): Path to Python executable
120
+ executable_name (str): Name of the executable to find (e.g., 'esptool', 'uv')
121
+
122
+ Returns:
123
+ str: Path to executable or fallback to executable name
124
+ """
125
+ if not python_exe or not os .path .isfile (python_exe ):
126
+ return executable_name # Fallback to command name
127
+
128
+ python_dir = os .path .dirname (python_exe )
129
+
130
+ if sys .platform == "win32" :
131
+ scripts_dir = os .path .join (python_dir , "Scripts" )
132
+ executable_path = os .path .join (scripts_dir , f"{ executable_name } .exe" )
133
+ else :
134
+ # For Unix-like systems, executables are typically in the same directory as python
135
+ # or in a bin subdirectory
136
+ executable_path = os .path .join (python_dir , executable_name )
137
+
138
+ # If not found in python directory, try bin subdirectory
139
+ if not os .path .isfile (executable_path ):
140
+ bin_dir = os .path .join (python_dir , "bin" )
141
+ executable_path = os .path .join (bin_dir , executable_name )
142
+
143
+ if os .path .isfile (executable_path ):
144
+ return executable_path
145
+
146
+ return executable_name # Fallback to command name
147
+
148
+
149
+ def _get_esptool_executable_path (python_exe ):
150
+ """
151
+ Get the path to the esptool executable binary.
152
+
153
+ Args:
154
+ python_exe (str): Path to Python executable
155
+
156
+ Returns:
157
+ str: Path to esptool executable
158
+ """
159
+ return _get_executable_path (python_exe , "esptool" )
160
+
161
+
162
+ def _get_uv_executable_path (python_exe ):
163
+ """
164
+ Get the path to the uv executable binary.
165
+
166
+ Args:
167
+ python_exe (str): Path to Python executable
168
+
169
+ Returns:
170
+ str: Path to uv executable
171
+ """
172
+ return _get_executable_path (python_exe , "uv" )
173
+
174
+
114
175
def get_packages_to_install (deps , installed_packages ):
115
176
"""
116
177
Generator for Python packages that need to be installed.
@@ -138,9 +199,12 @@ def install_python_deps():
138
199
Returns:
139
200
bool: True if successful, False otherwise
140
201
"""
202
+ # Get uv executable path
203
+ uv_executable = _get_uv_executable_path (env .subst ("$PYTHONEXE" ))
204
+
141
205
try :
142
206
result = subprocess .run (
143
- ["uv" , "--version" ],
207
+ [uv_executable , "--version" ],
144
208
capture_output = True ,
145
209
text = True ,
146
210
timeout = 3
@@ -162,6 +226,17 @@ def install_python_deps():
162
226
if result .stderr :
163
227
print (f"Error output: { result .stderr .strip ()} " )
164
228
return False
229
+
230
+ # Update uv executable path after installation
231
+ uv_executable = _get_uv_executable_path (env .subst ("$PYTHONEXE" ))
232
+
233
+ # Add Scripts directory to PATH for Windows
234
+ if sys .platform == "win32" :
235
+ python_dir = os .path .dirname (env .subst ("$PYTHONEXE" ))
236
+ scripts_dir = os .path .join (python_dir , "Scripts" )
237
+ if os .path .isdir (scripts_dir ):
238
+ os .environ ["PATH" ] = scripts_dir + os .pathsep + os .environ .get ("PATH" , "" )
239
+
165
240
except subprocess .TimeoutExpired :
166
241
print ("Error: uv installation timed out" )
167
242
return False
@@ -182,7 +257,7 @@ def _get_installed_uv_packages():
182
257
"""
183
258
result = {}
184
259
try :
185
- cmd = ["uv" , "pip" , "list" , "--format=json" ]
260
+ cmd = [uv_executable , "pip" , "list" , "--format=json" ]
186
261
result_obj = subprocess .run (
187
262
cmd ,
188
263
capture_output = True ,
@@ -221,7 +296,7 @@ def _get_installed_uv_packages():
221
296
packages_list = [f"{ p } { python_deps [p ]} " for p in packages_to_install ]
222
297
223
298
cmd = [
224
- "uv" , "pip" , "install" ,
299
+ uv_executable , "pip" , "install" ,
225
300
f"--python={ env .subst ('$PYTHONEXE' )} " ,
226
301
"--quiet" , "--upgrade"
227
302
] + packages_list
@@ -265,56 +340,30 @@ def install_esptool(env):
265
340
Returns:
266
341
str: Path to esptool executable, or 'esptool' as fallback
267
342
"""
268
- def _get_esptool_executable_path (python_exe ):
269
- """
270
- Get the path to the esptool executable binary.
271
-
272
- Args:
273
- python_exe (str): Path to Python executable
274
-
275
- Returns:
276
- str: Path to esptool executable
277
- """
278
- if not python_exe or not os .path .isfile (python_exe ):
279
- return 'esptool' # Fallback
280
-
281
- python_dir = os .path .dirname (python_exe )
282
-
283
- if sys .platform == "win32" :
284
- scripts_dir = os .path .join (python_dir , "Scripts" )
285
- esptool_exe = os .path .join (scripts_dir , "esptool.exe" )
286
- else :
287
- scripts_dir = os .path .join (python_dir )
288
- esptool_exe = os .path .join (scripts_dir , "esptool" )
289
-
290
- if os .path .isfile (esptool_exe ):
291
- return esptool_exe
292
-
293
- return 'esptool'
294
-
343
+ python_exe = env .subst ("$PYTHONEXE" )
344
+
295
345
try :
296
346
subprocess .check_call (
297
- [env . subst ( "$PYTHONEXE" ) , "-c" , "import esptool" ],
347
+ [python_exe , "-c" , "import esptool" ],
298
348
stdout = subprocess .DEVNULL ,
299
349
stderr = subprocess .DEVNULL ,
300
350
env = os .environ
301
351
)
302
- python_exe = env .subst ("$PYTHONEXE" )
303
352
esptool_binary_path = _get_esptool_executable_path (python_exe )
304
353
return esptool_binary_path
305
354
except (subprocess .CalledProcessError , FileNotFoundError ):
306
355
pass
307
356
308
357
esptool_repo_path = env .subst (platform .get_package_dir ("tool-esptoolpy" ) or "" )
309
358
if esptool_repo_path and os .path .isdir (esptool_repo_path ):
359
+ uv_executable = _get_uv_executable_path (python_exe )
310
360
try :
311
361
subprocess .check_call ([
312
- "uv" , "pip" , "install" , "--quiet" ,
313
- f"--python={ env . subst ( '$PYTHONEXE' ) } " ,
362
+ uv_executable , "pip" , "install" , "--quiet" ,
363
+ f"--python={ python_exe } " ,
314
364
"-e" , esptool_repo_path
315
365
], env = os .environ )
316
366
317
- python_exe = env .subst ("$PYTHONEXE" )
318
367
esptool_binary_path = _get_esptool_executable_path (python_exe )
319
368
return esptool_binary_path
320
369
0 commit comments