From 888c48b56886b03398646be1217508830427bd75 Mon Sep 17 00:00:00 2001
From: Paul Moore
Date: Fri, 3 May 2024 07:49:46 +0100
Subject: [PATCH] Preload script wrappers at import time (#215)
---
distlib/scripts.py | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)
diff --git a/distlib/scripts.py b/distlib/scripts.py
index 01f225c..0cf6640 100644
--- a/distlib/scripts.py
+++ b/distlib/scripts.py
@@ -48,6 +48,25 @@
sys.exit(%(func)s())
'''
+# Pre-fetch the contents of all executable wrapper stubs.
+# This is to address https://github.com/pypa/pip/issues/12666.
+# When updating pip, we rename the old pip in place before installing the
+# new version. If we try to fetch a wrapper *after* that rename, the finder
+# machinery will be confused as the package is no longer available at the
+# location where it was imported from. So we load everything into memory in
+# advance.
+
+if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'):
+ # Issue 31: don't hardcode an absolute package name, but
+ # determine it relative to the current package
+ DISTLIB_PACKAGE = __name__.rsplit('.', 1)[0]
+
+ WRAPPERS = {
+ r.name: r.bytes
+ for r in finder(DISTLIB_PACKAGE).iterator("")
+ if r.name.endswith(".exe")
+ }
+
def enquote_executable(executable):
if ' ' in executable:
@@ -386,14 +405,11 @@ def _get_launcher(self, kind):
bits = '32'
platform_suffix = '-arm' if get_platform() == 'win-arm64' else ''
name = '%s%s%s.exe' % (kind, bits, platform_suffix)
- # Issue 31: don't hardcode an absolute package name, but
- # determine it relative to the current package
- distlib_package = __name__.rsplit('.', 1)[0]
- resource = finder(distlib_package).find(name)
- if not resource:
- msg = ('Unable to find resource %s in package %s' % (name, distlib_package))
+ if name not in WRAPPERS:
+ msg = ('Unable to find resource %s in package %s' %
+ (name, DISTLIB_PACKAGE))
raise ValueError(msg)
- return resource.bytes
+ return WRAPPERS[name]
# Public API follows