python (3.11.7)
       1  # don't import any costly modules
       2  import sys
       3  import os
       4  
       5  
       6  is_pypy = '__pypy__' in sys.builtin_module_names
       7  
       8  
       9  def warn_distutils_present():
      10      if 'distutils' not in sys.modules:
      11          return
      12      if is_pypy and sys.version_info < (3, 7):
      13          # PyPy for 3.6 unconditionally imports distutils, so bypass the warning
      14          # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
      15          return
      16      import warnings
      17  
      18      warnings.warn(
      19          "Distutils was imported before Setuptools, but importing Setuptools "
      20          "also replaces the `distutils` module in `sys.modules`. This may lead "
      21          "to undesirable behaviors or errors. To avoid these issues, avoid "
      22          "using distutils directly, ensure that setuptools is installed in the "
      23          "traditional way (e.g. not an editable install), and/or make sure "
      24          "that setuptools is always imported before distutils."
      25      )
      26  
      27  
      28  def clear_distutils():
      29      if 'distutils' not in sys.modules:
      30          return
      31      import warnings
      32  
      33      warnings.warn("Setuptools is replacing distutils.")
      34      mods = [
      35          name
      36          for name in sys.modules
      37          if name == "distutils" or name.startswith("distutils.")
      38      ]
      39      for name in mods:
      40          del sys.modules[name]
      41  
      42  
      43  def enabled():
      44      """
      45      Allow selection of distutils by environment variable.
      46      """
      47      which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
      48      return which == 'local'
      49  
      50  
      51  def ensure_local_distutils():
      52      import importlib
      53  
      54      clear_distutils()
      55  
      56      # With the DistutilsMetaFinder in place,
      57      # perform an import to cause distutils to be
      58      # loaded from setuptools._distutils. Ref #2906.
      59      with shim():
      60          importlib.import_module('distutils')
      61  
      62      # check that submodules load as expected
      63      core = importlib.import_module('distutils.core')
      64      assert '_distutils' in core.__file__, core.__file__
      65      assert 'setuptools._distutils.log' not in sys.modules
      66  
      67  
      68  def do_override():
      69      """
      70      Ensure that the local copy of distutils is preferred over stdlib.
      71  
      72      See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
      73      for more motivation.
      74      """
      75      if enabled():
      76          warn_distutils_present()
      77          ensure_local_distutils()
      78  
      79  
      80  class ESC[4;38;5;81m_TrivialRe:
      81      def __init__(self, *patterns):
      82          self._patterns = patterns
      83  
      84      def match(self, string):
      85          return all(pat in string for pat in self._patterns)
      86  
      87  
      88  class ESC[4;38;5;81mDistutilsMetaFinder:
      89      def find_spec(self, fullname, path, target=None):
      90          # optimization: only consider top level modules and those
      91          # found in the CPython test suite.
      92          if path is not None and not fullname.startswith('test.'):
      93              return
      94  
      95          method_name = 'spec_for_{fullname}'.format(**locals())
      96          method = getattr(self, method_name, lambda: None)
      97          return method()
      98  
      99      def spec_for_distutils(self):
     100          if self.is_cpython():
     101              return
     102  
     103          import importlib
     104          import importlib.abc
     105          import importlib.util
     106  
     107          try:
     108              mod = importlib.import_module('setuptools._distutils')
     109          except Exception:
     110              # There are a couple of cases where setuptools._distutils
     111              # may not be present:
     112              # - An older Setuptools without a local distutils is
     113              #   taking precedence. Ref #2957.
     114              # - Path manipulation during sitecustomize removes
     115              #   setuptools from the path but only after the hook
     116              #   has been loaded. Ref #2980.
     117              # In either case, fall back to stdlib behavior.
     118              return
     119  
     120          class ESC[4;38;5;81mDistutilsLoader(ESC[4;38;5;149mimportlibESC[4;38;5;149m.ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mLoader):
     121              def create_module(self, spec):
     122                  mod.__name__ = 'distutils'
     123                  return mod
     124  
     125              def exec_module(self, module):
     126                  pass
     127  
     128          return importlib.util.spec_from_loader(
     129              'distutils', DistutilsLoader(), origin=mod.__file__
     130          )
     131  
     132      @staticmethod
     133      def is_cpython():
     134          """
     135          Suppress supplying distutils for CPython (build and tests).
     136          Ref #2965 and #3007.
     137          """
     138          return os.path.isfile('pybuilddir.txt')
     139  
     140      def spec_for_pip(self):
     141          """
     142          Ensure stdlib distutils when running under pip.
     143          See pypa/pip#8761 for rationale.
     144          """
     145          if self.pip_imported_during_build():
     146              return
     147          clear_distutils()
     148          self.spec_for_distutils = lambda: None
     149  
     150      @classmethod
     151      def pip_imported_during_build(cls):
     152          """
     153          Detect if pip is being imported in a build script. Ref #2355.
     154          """
     155          import traceback
     156  
     157          return any(
     158              cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
     159          )
     160  
     161      @staticmethod
     162      def frame_file_is_setup(frame):
     163          """
     164          Return True if the indicated frame suggests a setup.py file.
     165          """
     166          # some frames may not have __file__ (#2940)
     167          return frame.f_globals.get('__file__', '').endswith('setup.py')
     168  
     169      def spec_for_sensitive_tests(self):
     170          """
     171          Ensure stdlib distutils when running select tests under CPython.
     172  
     173          python/cpython#91169
     174          """
     175          clear_distutils()
     176          self.spec_for_distutils = lambda: None
     177  
     178      sensitive_tests = (
     179          [
     180              'test.test_distutils',
     181              'test.test_peg_generator',
     182              'test.test_importlib',
     183          ]
     184          if sys.version_info < (3, 10)
     185          else [
     186              'test.test_distutils',
     187          ]
     188      )
     189  
     190  
     191  for name in DistutilsMetaFinder.sensitive_tests:
     192      setattr(
     193          DistutilsMetaFinder,
     194          f'spec_for_{name}',
     195          DistutilsMetaFinder.spec_for_sensitive_tests,
     196      )
     197  
     198  
     199  DISTUTILS_FINDER = DistutilsMetaFinder()
     200  
     201  
     202  def add_shim():
     203      DISTUTILS_FINDER in sys.meta_path or insert_shim()
     204  
     205  
     206  class ESC[4;38;5;81mshim:
     207      def __enter__(self):
     208          insert_shim()
     209  
     210      def __exit__(self, exc, value, tb):
     211          remove_shim()
     212  
     213  
     214  def insert_shim():
     215      sys.meta_path.insert(0, DISTUTILS_FINDER)
     216  
     217  
     218  def remove_shim():
     219      try:
     220          sys.meta_path.remove(DISTUTILS_FINDER)
     221      except ValueError:
     222          pass