@@ -102,22 +102,23 @@ func determineSourceDir(extractDir string) string {
102102 return extractDir
103103}
104104
105- // installPipIfNeeded installs pip on Windows or shows success message on Unix
105+ // installPipIfNeeded ensures pip is properly installed and accessible.
106+ // On Windows, pip may be missing (python.org embeddable) or have broken
107+ // executables (python-build-standalone with embedded build paths).
108+ // Running ensurepip --default-pip --upgrade creates working pip executables.
106109func (p * Provider ) installPipIfNeeded (version string ) {
107110 if goruntime .GOOS == constants .OSWindows {
108- // Windows embeddable packages need pip installed
109- pipSpinner := ui .NewSpinner ("Installing pip..." )
111+ pipSpinner := ui .NewSpinner ("Configuring pip..." )
110112 pipSpinner .Start ()
111113 if err := p .installPip (version ); err != nil {
112- pipSpinner .Warning ("Failed to install pip" )
113- ui .Info ("To install pip manually:" )
114- ui .Info (" 1. Download: %s" , p .getPipURL (version ))
115- ui .Info (" 2. Run: python get-pip.py" )
114+ pipSpinner .Warning ("Failed to configure pip" )
115+ ui .Info ("To install pip manually, run:" )
116+ ui .Info (" python -m ensurepip --default-pip --upgrade" )
116117 } else {
117- pipSpinner .Success ("pip installed successfully" )
118+ pipSpinner .Success ("pip configured successfully" )
118119 }
119120 } else {
120- // python-build-standalone includes pip
121+ // python-build-standalone includes pip on Unix
121122 ui .Success ("pip included" )
122123 }
123124}
@@ -169,7 +170,10 @@ func (p *Provider) Install(version string) error {
169170 return fmt .Errorf ("failed to move to install location: %w" , err )
170171 }
171172
172- // Create shims
173+ // Install/configure pip first (so executables exist before creating shims)
174+ p .installPipIfNeeded (version )
175+
176+ // Create shims (after pip is installed, all executables now exist)
173177 shimSpinner := ui .NewSpinner ("Creating shims..." )
174178 shimSpinner .Start ()
175179 if err := p .createShims (); err != nil {
@@ -181,9 +185,6 @@ func (p *Provider) Install(version string) error {
181185 ui .Success ("Python v%s installed successfully" , version )
182186 ui .Info ("Location: %s" , installPath )
183187
184- // Install/verify pip
185- p .installPipIfNeeded (version )
186-
187188 return nil
188189}
189190
@@ -222,7 +223,13 @@ func (p *Provider) createShims() error {
222223 return manager .CreateShims (shimNames )
223224}
224225
225- // installPip installs pip for Windows embeddable Python packages
226+ // installPip ensures pip is properly installed with working executables.
227+ // This handles two scenarios:
228+ // 1. python.org embeddable packages: pip is not included, needs ensurepip
229+ // 2. python-build-standalone: pip module exists but pip.exe has broken paths
230+ //
231+ // Running "python -m ensurepip --default-pip --upgrade" handles both cases
232+ // by (re)installing pip and creating working pip/pip3/pipX.Y executables.
226233func (p * Provider ) installPip (version string ) error {
227234 pythonPath , err := p .ExecutablePath (version )
228235 if err != nil {
@@ -231,25 +238,38 @@ func (p *Provider) installPip(version string) error {
231238
232239 installPath := config .RuntimeVersionPath ("python" , version )
233240
234- // For embeddable packages, we need to:
235- // 1. Modify python311._pth to enable site-packages
236- // 2. Download and run get-pip.py
237-
238- // Step 1: Enable site-packages by uncommenting the import site line
241+ // For python.org embeddable packages, enable site-packages first.
242+ // This file doesn't exist in python-build-standalone, so errors are ignored.
239243 pthFile := filepath .Join (installPath , fmt .Sprintf ("python%s._pth" , strings .Join (strings .Split (version , "." )[:2 ], "" )))
240- if err := p .enableSitePackages (pthFile ); err != nil {
241- return fmt .Errorf ("failed to enable site-packages: %w" , err )
244+ _ = p .enableSitePackages (pthFile ) // Best effort - ignore errors
245+
246+ // Run ensurepip to install/reinstall pip with working executables.
247+ // --default-pip: creates pip.exe in addition to pipX.exe and pipX.Y.exe
248+ // --upgrade: reinstalls even if pip module already exists (fixes broken executables)
249+ cmd := exec .Command (pythonPath , "-m" , "ensurepip" , "--default-pip" , "--upgrade" )
250+ cmd .Dir = installPath
251+ output , err := cmd .CombinedOutput ()
252+ if err != nil {
253+ ui .Debug ("ensurepip failed: %v\n Output: %s" , err , string (output ))
254+ // Fall back to get-pip.py for older Python versions or edge cases
255+ return p .installPipWithGetPip (version , pythonPath , installPath )
242256 }
243257
244- // Step 2: Download get-pip.py (use version-specific URL for older Python)
258+ return nil
259+ }
260+
261+ // installPipWithGetPip is a fallback method that downloads and runs get-pip.py.
262+ // Used when ensurepip fails (e.g., ensurepip module missing or corrupted).
263+ func (p * Provider ) installPipWithGetPip (version , pythonPath , installPath string ) error {
264+ ui .Debug ("Falling back to get-pip.py" )
265+
245266 getPipURL := p .getPipURL (version )
246267 getPipPath := filepath .Join (installPath , "get-pip.py" )
247268 if err := download .File (getPipURL , getPipPath ); err != nil {
248269 return fmt .Errorf ("failed to download get-pip.py: %w" , err )
249270 }
250271 defer func () { _ = os .Remove (getPipPath ) }()
251272
252- // Step 3: Run get-pip.py
253273 cmd := exec .Command (pythonPath , getPipPath )
254274 cmd .Dir = installPath
255275 output , err := cmd .CombinedOutput ()
0 commit comments