python (3.11.7)

(root)/
lib/
python3.11/
site-packages/
setuptools/
command/
test.py
       1  import os
       2  import operator
       3  import sys
       4  import contextlib
       5  import itertools
       6  import unittest
       7  from distutils.errors import DistutilsError, DistutilsOptionError
       8  from distutils import log
       9  from unittest import TestLoader
      10  
      11  from pkg_resources import (
      12      resource_listdir,
      13      resource_exists,
      14      normalize_path,
      15      working_set,
      16      evaluate_marker,
      17      add_activation_listener,
      18      require,
      19  )
      20  from .._importlib import metadata
      21  from setuptools import Command
      22  from setuptools.extern.more_itertools import unique_everseen
      23  from setuptools.extern.jaraco.functools import pass_none
      24  
      25  
      26  class ESC[4;38;5;81mScanningLoader(ESC[4;38;5;149mTestLoader):
      27      def __init__(self):
      28          TestLoader.__init__(self)
      29          self._visited = set()
      30  
      31      def loadTestsFromModule(self, module, pattern=None):
      32          """Return a suite of all tests cases contained in the given module
      33  
      34          If the module is a package, load tests from all the modules in it.
      35          If the module has an ``additional_tests`` function, call it and add
      36          the return value to the tests.
      37          """
      38          if module in self._visited:
      39              return None
      40          self._visited.add(module)
      41  
      42          tests = []
      43          tests.append(TestLoader.loadTestsFromModule(self, module))
      44  
      45          if hasattr(module, "additional_tests"):
      46              tests.append(module.additional_tests())
      47  
      48          if hasattr(module, '__path__'):
      49              for file in resource_listdir(module.__name__, ''):
      50                  if file.endswith('.py') and file != '__init__.py':
      51                      submodule = module.__name__ + '.' + file[:-3]
      52                  else:
      53                      if resource_exists(module.__name__, file + '/__init__.py'):
      54                          submodule = module.__name__ + '.' + file
      55                      else:
      56                          continue
      57                  tests.append(self.loadTestsFromName(submodule))
      58  
      59          if len(tests) != 1:
      60              return self.suiteClass(tests)
      61          else:
      62              return tests[0]  # don't create a nested suite for only one return
      63  
      64  
      65  # adapted from jaraco.classes.properties:NonDataProperty
      66  class ESC[4;38;5;81mNonDataProperty:
      67      def __init__(self, fget):
      68          self.fget = fget
      69  
      70      def __get__(self, obj, objtype=None):
      71          if obj is None:
      72              return self
      73          return self.fget(obj)
      74  
      75  
      76  class ESC[4;38;5;81mtest(ESC[4;38;5;149mCommand):
      77      """Command to run unit tests after in-place build"""
      78  
      79      description = "run unit tests after in-place build (deprecated)"
      80  
      81      user_options = [
      82          ('test-module=', 'm', "Run 'test_suite' in specified module"),
      83          (
      84              'test-suite=',
      85              's',
      86              "Run single test, case or suite (e.g. 'module.test_suite')",
      87          ),
      88          ('test-runner=', 'r', "Test runner to use"),
      89      ]
      90  
      91      def initialize_options(self):
      92          self.test_suite = None
      93          self.test_module = None
      94          self.test_loader = None
      95          self.test_runner = None
      96  
      97      def finalize_options(self):
      98  
      99          if self.test_suite and self.test_module:
     100              msg = "You may specify a module or a suite, but not both"
     101              raise DistutilsOptionError(msg)
     102  
     103          if self.test_suite is None:
     104              if self.test_module is None:
     105                  self.test_suite = self.distribution.test_suite
     106              else:
     107                  self.test_suite = self.test_module + ".test_suite"
     108  
     109          if self.test_loader is None:
     110              self.test_loader = getattr(self.distribution, 'test_loader', None)
     111          if self.test_loader is None:
     112              self.test_loader = "setuptools.command.test:ScanningLoader"
     113          if self.test_runner is None:
     114              self.test_runner = getattr(self.distribution, 'test_runner', None)
     115  
     116      @NonDataProperty
     117      def test_args(self):
     118          return list(self._test_args())
     119  
     120      def _test_args(self):
     121          if not self.test_suite:
     122              yield 'discover'
     123          if self.verbose:
     124              yield '--verbose'
     125          if self.test_suite:
     126              yield self.test_suite
     127  
     128      def with_project_on_sys_path(self, func):
     129          """
     130          Backward compatibility for project_on_sys_path context.
     131          """
     132          with self.project_on_sys_path():
     133              func()
     134  
     135      @contextlib.contextmanager
     136      def project_on_sys_path(self, include_dists=[]):
     137          self.run_command('egg_info')
     138  
     139          # Build extensions in-place
     140          self.reinitialize_command('build_ext', inplace=1)
     141          self.run_command('build_ext')
     142  
     143          ei_cmd = self.get_finalized_command("egg_info")
     144  
     145          old_path = sys.path[:]
     146          old_modules = sys.modules.copy()
     147  
     148          try:
     149              project_path = normalize_path(ei_cmd.egg_base)
     150              sys.path.insert(0, project_path)
     151              working_set.__init__()
     152              add_activation_listener(lambda dist: dist.activate())
     153              require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
     154              with self.paths_on_pythonpath([project_path]):
     155                  yield
     156          finally:
     157              sys.path[:] = old_path
     158              sys.modules.clear()
     159              sys.modules.update(old_modules)
     160              working_set.__init__()
     161  
     162      @staticmethod
     163      @contextlib.contextmanager
     164      def paths_on_pythonpath(paths):
     165          """
     166          Add the indicated paths to the head of the PYTHONPATH environment
     167          variable so that subprocesses will also see the packages at
     168          these paths.
     169  
     170          Do this in a context that restores the value on exit.
     171          """
     172          nothing = object()
     173          orig_pythonpath = os.environ.get('PYTHONPATH', nothing)
     174          current_pythonpath = os.environ.get('PYTHONPATH', '')
     175          try:
     176              prefix = os.pathsep.join(unique_everseen(paths))
     177              to_join = filter(None, [prefix, current_pythonpath])
     178              new_path = os.pathsep.join(to_join)
     179              if new_path:
     180                  os.environ['PYTHONPATH'] = new_path
     181              yield
     182          finally:
     183              if orig_pythonpath is nothing:
     184                  os.environ.pop('PYTHONPATH', None)
     185              else:
     186                  os.environ['PYTHONPATH'] = orig_pythonpath
     187  
     188      @staticmethod
     189      def install_dists(dist):
     190          """
     191          Install the requirements indicated by self.distribution and
     192          return an iterable of the dists that were built.
     193          """
     194          ir_d = dist.fetch_build_eggs(dist.install_requires)
     195          tr_d = dist.fetch_build_eggs(dist.tests_require or [])
     196          er_d = dist.fetch_build_eggs(
     197              v
     198              for k, v in dist.extras_require.items()
     199              if k.startswith(':') and evaluate_marker(k[1:])
     200          )
     201          return itertools.chain(ir_d, tr_d, er_d)
     202  
     203      def run(self):
     204          self.announce(
     205              "WARNING: Testing via this command is deprecated and will be "
     206              "removed in a future version. Users looking for a generic test "
     207              "entry point independent of test runner are encouraged to use "
     208              "tox.",
     209              log.WARN,
     210          )
     211  
     212          installed_dists = self.install_dists(self.distribution)
     213  
     214          cmd = ' '.join(self._argv)
     215          if self.dry_run:
     216              self.announce('skipping "%s" (dry run)' % cmd)
     217              return
     218  
     219          self.announce('running "%s"' % cmd)
     220  
     221          paths = map(operator.attrgetter('location'), installed_dists)
     222          with self.paths_on_pythonpath(paths):
     223              with self.project_on_sys_path():
     224                  self.run_tests()
     225  
     226      def run_tests(self):
     227          test = unittest.main(
     228              None,
     229              None,
     230              self._argv,
     231              testLoader=self._resolve_as_ep(self.test_loader),
     232              testRunner=self._resolve_as_ep(self.test_runner),
     233              exit=False,
     234          )
     235          if not test.result.wasSuccessful():
     236              msg = 'Test failed: %s' % test.result
     237              self.announce(msg, log.ERROR)
     238              raise DistutilsError(msg)
     239  
     240      @property
     241      def _argv(self):
     242          return ['unittest'] + self.test_args
     243  
     244      @staticmethod
     245      @pass_none
     246      def _resolve_as_ep(val):
     247          """
     248          Load the indicated attribute value, called, as a as if it were
     249          specified as an entry point.
     250          """
     251          return metadata.EntryPoint(value=val, name=None, group=None).load()()