GetPythonExecutable attempts to find or create Python via conda environments.
()
| 116 | |
| 117 | // GetPythonExecutable attempts to find or create Python via conda environments. |
| 118 | func (c *CondaPython) GetExecutable() (string, error) { |
| 119 | // conda binary must be provided and exist |
| 120 | if c.condaBinary == "" || !fileio.PathExists(c.condaBinary) { |
| 121 | return "", fmt.Errorf("conda binary is required") |
| 122 | } |
| 123 | |
| 124 | // Normalize version to minor version (e.g., 3.11.0 -> 3.11). |
| 125 | minorVersion := c.pythonVersion |
| 126 | if strings.Count(c.pythonVersion, ".") > 1 { |
| 127 | parts := strings.Split(c.pythonVersion, ".") |
| 128 | minorVersion = parts[0] + "." + parts[1] |
| 129 | } |
| 130 | |
| 131 | // Use underscore in environment name instead of dots (py311 instead of python3.11). |
| 132 | // This avoids issues with dots in environment names. |
| 133 | envName := fmt.Sprintf("py%s", strings.ReplaceAll(minorVersion, ".", "")) |
| 134 | |
| 135 | // Try to find existing environment |
| 136 | cmd := exec.Command(c.condaBinary, "run", "-n", envName, "python", "--version") |
| 137 | if err := cmd.Run(); err == nil { |
| 138 | var ( |
| 139 | output []byte |
| 140 | err error |
| 141 | ) |
| 142 | |
| 143 | // Environment exists, get the full path using platform-specific method. |
| 144 | if runtime.GOOS == "windows" { |
| 145 | output, err = exec.Command(c.condaBinary, "run", "-n", envName, "python", "-c", "import sys; print(sys.executable)").Output() |
| 146 | } else { |
| 147 | output, err = exec.Command(c.condaBinary, "run", "-n", envName, "which", "python").Output() |
| 148 | } |
| 149 | if err != nil { |
| 150 | return "", fmt.Errorf("failed to get Python executable path: %w", err) |
| 151 | } |
| 152 | |
| 153 | if len(output) > 0 { |
| 154 | return strings.TrimSpace(string(output)), nil |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | // Environment not found, attempt to create it with the specified Python version. |
| 159 | // Use conda-forge channel as the default source. |
| 160 | color.Printf(color.Hint, "- creating conda environment for Python %s (venv name: %s)", minorVersion, envName) |
| 161 | createCmd := exec.Command(c.condaBinary, "create", "-y", "-c", "conda-forge", "-n", envName, fmt.Sprintf("python=%s", minorVersion)) |
| 162 | if output, err := createCmd.CombinedOutput(); err != nil { |
| 163 | return "", fmt.Errorf("failed to create conda environment for Python %s -> %s -> %w", |
| 164 | minorVersion, string(output), err) |
| 165 | } |
| 166 | color.PrintInline(color.Hint, "✔ creating conda environment for Python %s (venv name: %s)\n", minorVersion, envName) |
| 167 | |
| 168 | // Verify the new environment was created. |
| 169 | cmd = exec.Command(c.condaBinary, "run", "-n", envName, "python", "--version") |
| 170 | if err := cmd.Run(); err != nil { |
| 171 | return "", fmt.Errorf("python environment verification failed: %w", err) |
| 172 | } |
| 173 | |
| 174 | // Get the path to the python executable in this environment. |
| 175 | var output []byte |
nothing calls this directly
no test coverage detected