summaryrefslogtreecommitdiffstats
path: root/third_party/python/setuptools/_distutils_hack/__init__.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 15:11:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 15:11:27 +0000
commitf3bcaf9f88aad2c423ebcd61121562f9834187d4 (patch)
treef22238c29b57707b645a350940e3e9bdf3ce1f5d /third_party/python/setuptools/_distutils_hack/__init__.py
parentAdding debian version 115.7.0esr-1~deb12u1. (diff)
downloadfirefox-esr-f3bcaf9f88aad2c423ebcd61121562f9834187d4.tar.xz
firefox-esr-f3bcaf9f88aad2c423ebcd61121562f9834187d4.zip
Merging upstream version 115.8.0esr.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/python/setuptools/_distutils_hack/__init__.py')
-rw-r--r--third_party/python/setuptools/_distutils_hack/__init__.py144
1 files changed, 124 insertions, 20 deletions
diff --git a/third_party/python/setuptools/_distutils_hack/__init__.py b/third_party/python/setuptools/_distutils_hack/__init__.py
index c31edfed17..b951c2defd 100644
--- a/third_party/python/setuptools/_distutils_hack/__init__.py
+++ b/third_party/python/setuptools/_distutils_hack/__init__.py
@@ -1,8 +1,6 @@
+# don't import any costly modules
import sys
import os
-import re
-import importlib
-import warnings
is_pypy = '__pypy__' in sys.builtin_module_names
@@ -15,20 +13,29 @@ def warn_distutils_present():
# PyPy for 3.6 unconditionally imports distutils, so bypass the warning
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
return
+ import warnings
+
warnings.warn(
"Distutils was imported before Setuptools, but importing Setuptools "
"also replaces the `distutils` module in `sys.modules`. This may lead "
"to undesirable behaviors or errors. To avoid these issues, avoid "
"using distutils directly, ensure that setuptools is installed in the "
"traditional way (e.g. not an editable install), and/or make sure "
- "that setuptools is always imported before distutils.")
+ "that setuptools is always imported before distutils."
+ )
def clear_distutils():
if 'distutils' not in sys.modules:
return
+ import warnings
+
warnings.warn("Setuptools is replacing distutils.")
- mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
+ mods = [
+ name
+ for name in sys.modules
+ if name == "distutils" or name.startswith("distutils.")
+ ]
for name in mods:
del sys.modules[name]
@@ -37,19 +44,25 @@ def enabled():
"""
Allow selection of distutils by environment variable.
"""
- which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
+ which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
return which == 'local'
def ensure_local_distutils():
+ import importlib
+
clear_distutils()
- distutils = importlib.import_module('setuptools._distutils')
- distutils.__name__ = 'distutils'
- sys.modules['distutils'] = distutils
- # sanity check that submodules load as expected
+ # With the DistutilsMetaFinder in place,
+ # perform an import to cause distutils to be
+ # loaded from setuptools._distutils. Ref #2906.
+ with shim():
+ importlib.import_module('distutils')
+
+ # check that submodules load as expected
core = importlib.import_module('distutils.core')
assert '_distutils' in core.__file__, core.__file__
+ assert 'setuptools._distutils.log' not in sys.modules
def do_override():
@@ -64,9 +77,19 @@ def do_override():
ensure_local_distutils()
+class _TrivialRe:
+ def __init__(self, *patterns):
+ self._patterns = patterns
+
+ def match(self, string):
+ return all(pat in string for pat in self._patterns)
+
+
class DistutilsMetaFinder:
def find_spec(self, fullname, path, target=None):
- if path is not None:
+ # optimization: only consider top level modules and those
+ # found in the CPython test suite.
+ if path is not None and not fullname.startswith('test.'):
return
method_name = 'spec_for_{fullname}'.format(**locals())
@@ -74,50 +97,131 @@ class DistutilsMetaFinder:
return method()
def spec_for_distutils(self):
+ if self.is_cpython():
+ return
+
+ import importlib
import importlib.abc
import importlib.util
- class DistutilsLoader(importlib.abc.Loader):
+ try:
+ mod = importlib.import_module('setuptools._distutils')
+ except Exception:
+ # There are a couple of cases where setuptools._distutils
+ # may not be present:
+ # - An older Setuptools without a local distutils is
+ # taking precedence. Ref #2957.
+ # - Path manipulation during sitecustomize removes
+ # setuptools from the path but only after the hook
+ # has been loaded. Ref #2980.
+ # In either case, fall back to stdlib behavior.
+ return
+ class DistutilsLoader(importlib.abc.Loader):
def create_module(self, spec):
- return importlib.import_module('setuptools._distutils')
+ mod.__name__ = 'distutils'
+ return mod
def exec_module(self, module):
pass
- return importlib.util.spec_from_loader('distutils', DistutilsLoader())
+ return importlib.util.spec_from_loader(
+ 'distutils', DistutilsLoader(), origin=mod.__file__
+ )
+
+ @staticmethod
+ def is_cpython():
+ """
+ Suppress supplying distutils for CPython (build and tests).
+ Ref #2965 and #3007.
+ """
+ return os.path.isfile('pybuilddir.txt')
def spec_for_pip(self):
"""
Ensure stdlib distutils when running under pip.
See pypa/pip#8761 for rationale.
"""
- if self.pip_imported_during_build():
+ if sys.version_info >= (3, 12) or self.pip_imported_during_build():
return
clear_distutils()
self.spec_for_distutils = lambda: None
- @staticmethod
- def pip_imported_during_build():
+ @classmethod
+ def pip_imported_during_build(cls):
"""
Detect if pip is being imported in a build script. Ref #2355.
"""
import traceback
+
return any(
- frame.f_globals['__file__'].endswith('setup.py')
- for frame, line in traceback.walk_stack(None)
+ cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
)
+ @staticmethod
+ def frame_file_is_setup(frame):
+ """
+ Return True if the indicated frame suggests a setup.py file.
+ """
+ # some frames may not have __file__ (#2940)
+ return frame.f_globals.get('__file__', '').endswith('setup.py')
+
+ def spec_for_sensitive_tests(self):
+ """
+ Ensure stdlib distutils when running select tests under CPython.
+
+ python/cpython#91169
+ """
+ clear_distutils()
+ self.spec_for_distutils = lambda: None
+
+ sensitive_tests = (
+ [
+ 'test.test_distutils',
+ 'test.test_peg_generator',
+ 'test.test_importlib',
+ ]
+ if sys.version_info < (3, 10)
+ else [
+ 'test.test_distutils',
+ ]
+ )
+
+
+for name in DistutilsMetaFinder.sensitive_tests:
+ setattr(
+ DistutilsMetaFinder,
+ f'spec_for_{name}',
+ DistutilsMetaFinder.spec_for_sensitive_tests,
+ )
+
DISTUTILS_FINDER = DistutilsMetaFinder()
def add_shim():
+ DISTUTILS_FINDER in sys.meta_path or insert_shim()
+
+
+class shim:
+ def __enter__(self):
+ insert_shim()
+
+ def __exit__(self, exc, value, tb):
+ _remove_shim()
+
+
+def insert_shim():
sys.meta_path.insert(0, DISTUTILS_FINDER)
-def remove_shim():
+def _remove_shim():
try:
sys.meta_path.remove(DISTUTILS_FINDER)
except ValueError:
pass
+
+
+if sys.version_info < (3, 12):
+ # DistutilsMetaFinder can only be disabled in Python < 3.12 (PEP 632)
+ remove_shim = _remove_shim