(pythonPath: string, isExplicit: boolean)
| 232 | * @throws {Error} If no valid Python executable is found. |
| 233 | */ |
| 234 | export async function validatePythonPath(pythonPath: string, isExplicit: boolean): Promise<string> { |
| 235 | // Return cached result if available |
| 236 | if (state.cachedPythonPath) { |
| 237 | return state.cachedPythonPath; |
| 238 | } |
| 239 | |
| 240 | // Create validation promise atomically if it doesn't exist |
| 241 | // This prevents race conditions where multiple calls create separate validations |
| 242 | if (!state.validationPromise) { |
| 243 | state.validationPromise = (async () => { |
| 244 | try { |
| 245 | const primaryPath = await tryPath(pythonPath); |
| 246 | if (primaryPath) { |
| 247 | state.cachedPythonPath = primaryPath; |
| 248 | state.validationPromise = null; |
| 249 | return primaryPath; |
| 250 | } |
| 251 | |
| 252 | if (isExplicit) { |
| 253 | const error = new Error( |
| 254 | `Python 3 not found. Tried "${pythonPath}" ` + |
| 255 | `Please ensure Python 3 is installed and set the PROMPTFOO_PYTHON environment variable ` + |
| 256 | `to your Python 3 executable path (e.g., '${process.platform === 'win32' ? 'C:\\Python39\\python.exe' : '/usr/bin/python3'}').`, |
| 257 | ); |
| 258 | // Clear promise on error to allow retry |
| 259 | state.validationPromise = null; |
| 260 | throw error; |
| 261 | } |
| 262 | |
| 263 | // Try to get Python executable using comprehensive detection |
| 264 | const detectedPath = await getSysExecutable(); |
| 265 | if (detectedPath) { |
| 266 | state.cachedPythonPath = detectedPath; |
| 267 | state.validationPromise = null; |
| 268 | return detectedPath; |
| 269 | } |
| 270 | |
| 271 | const error = new Error( |
| 272 | `Python 3 not found. Tried "${pythonPath}", sys.executable detection, and fallback commands. ` + |
| 273 | `Please ensure Python 3 is installed and set the PROMPTFOO_PYTHON environment variable ` + |
| 274 | `to your Python 3 executable path (e.g., '${process.platform === 'win32' ? 'C:\\Python39\\python.exe' : '/usr/bin/python3'}').`, |
| 275 | ); |
| 276 | // Clear promise on error to allow retry |
| 277 | state.validationPromise = null; |
| 278 | throw error; |
| 279 | } catch (error) { |
| 280 | // Ensure promise is cleared on any error |
| 281 | state.validationPromise = null; |
| 282 | throw error; |
| 283 | } |
| 284 | })(); |
| 285 | } |
| 286 | |
| 287 | // Return the existing or newly-created promise |
| 288 | return state.validationPromise; |
| 289 | } |
| 290 | |
| 291 | /** |
no test coverage detected
searching dependent graphs…