(root)/
Python-3.11.7/
Lib/
unittest/
main.py
       1  """Unittest main program"""
       2  
       3  import sys
       4  import argparse
       5  import os
       6  import warnings
       7  
       8  from . import loader, runner
       9  from .signals import installHandler
      10  
      11  __unittest = True
      12  
      13  MAIN_EXAMPLES = """\
      14  Examples:
      15    %(prog)s test_module               - run tests from test_module
      16    %(prog)s module.TestClass          - run tests from module.TestClass
      17    %(prog)s module.Class.test_method  - run specified test method
      18    %(prog)s path/to/test_file.py      - run tests from test_file.py
      19  """
      20  
      21  MODULE_EXAMPLES = """\
      22  Examples:
      23    %(prog)s                           - run default set of tests
      24    %(prog)s MyTestSuite               - run suite 'MyTestSuite'
      25    %(prog)s MyTestCase.testSomething  - run MyTestCase.testSomething
      26    %(prog)s MyTestCase                - run all 'test*' test methods
      27                                         in MyTestCase
      28  """
      29  
      30  def _convert_name(name):
      31      # on Linux / Mac OS X 'foo.PY' is not importable, but on
      32      # Windows it is. Simpler to do a case insensitive match
      33      # a better check would be to check that the name is a
      34      # valid Python module name.
      35      if os.path.isfile(name) and name.lower().endswith('.py'):
      36          if os.path.isabs(name):
      37              rel_path = os.path.relpath(name, os.getcwd())
      38              if os.path.isabs(rel_path) or rel_path.startswith(os.pardir):
      39                  return name
      40              name = rel_path
      41          # on Windows both '\' and '/' are used as path
      42          # separators. Better to replace both than rely on os.path.sep
      43          return os.path.normpath(name)[:-3].replace('\\', '.').replace('/', '.')
      44      return name
      45  
      46  def _convert_names(names):
      47      return [_convert_name(name) for name in names]
      48  
      49  
      50  def _convert_select_pattern(pattern):
      51      if not '*' in pattern:
      52          pattern = '*%s*' % pattern
      53      return pattern
      54  
      55  
      56  class ESC[4;38;5;81mTestProgram(ESC[4;38;5;149mobject):
      57      """A command-line program that runs a set of tests; this is primarily
      58         for making test modules conveniently executable.
      59      """
      60      # defaults for testing
      61      module=None
      62      verbosity = 1
      63      failfast = catchbreak = buffer = progName = warnings = testNamePatterns = None
      64      _discovery_parser = None
      65  
      66      def __init__(self, module='__main__', defaultTest=None, argv=None,
      67                      testRunner=None, testLoader=loader.defaultTestLoader,
      68                      exit=True, verbosity=1, failfast=None, catchbreak=None,
      69                      buffer=None, warnings=None, *, tb_locals=False):
      70          if isinstance(module, str):
      71              self.module = __import__(module)
      72              for part in module.split('.')[1:]:
      73                  self.module = getattr(self.module, part)
      74          else:
      75              self.module = module
      76          if argv is None:
      77              argv = sys.argv
      78  
      79          self.exit = exit
      80          self.failfast = failfast
      81          self.catchbreak = catchbreak
      82          self.verbosity = verbosity
      83          self.buffer = buffer
      84          self.tb_locals = tb_locals
      85          if warnings is None and not sys.warnoptions:
      86              # even if DeprecationWarnings are ignored by default
      87              # print them anyway unless other warnings settings are
      88              # specified by the warnings arg or the -W python flag
      89              self.warnings = 'default'
      90          else:
      91              # here self.warnings is set either to the value passed
      92              # to the warnings args or to None.
      93              # If the user didn't pass a value self.warnings will
      94              # be None. This means that the behavior is unchanged
      95              # and depends on the values passed to -W.
      96              self.warnings = warnings
      97          self.defaultTest = defaultTest
      98          self.testRunner = testRunner
      99          self.testLoader = testLoader
     100          self.progName = os.path.basename(argv[0])
     101          self.parseArgs(argv)
     102          self.runTests()
     103  
     104      def usageExit(self, msg=None):
     105          warnings.warn("TestProgram.usageExit() is deprecated and will be"
     106                        " removed in Python 3.13", DeprecationWarning)
     107          if msg:
     108              print(msg)
     109          if self._discovery_parser is None:
     110              self._initArgParsers()
     111          self._print_help()
     112          sys.exit(2)
     113  
     114      def _print_help(self, *args, **kwargs):
     115          if self.module is None:
     116              print(self._main_parser.format_help())
     117              print(MAIN_EXAMPLES % {'prog': self.progName})
     118              self._discovery_parser.print_help()
     119          else:
     120              print(self._main_parser.format_help())
     121              print(MODULE_EXAMPLES % {'prog': self.progName})
     122  
     123      def parseArgs(self, argv):
     124          self._initArgParsers()
     125          if self.module is None:
     126              if len(argv) > 1 and argv[1].lower() == 'discover':
     127                  self._do_discovery(argv[2:])
     128                  return
     129              self._main_parser.parse_args(argv[1:], self)
     130              if not self.tests:
     131                  # this allows "python -m unittest -v" to still work for
     132                  # test discovery.
     133                  self._do_discovery([])
     134                  return
     135          else:
     136              self._main_parser.parse_args(argv[1:], self)
     137  
     138          if self.tests:
     139              self.testNames = _convert_names(self.tests)
     140              if __name__ == '__main__':
     141                  # to support python -m unittest ...
     142                  self.module = None
     143          elif self.defaultTest is None:
     144              # createTests will load tests from self.module
     145              self.testNames = None
     146          elif isinstance(self.defaultTest, str):
     147              self.testNames = (self.defaultTest,)
     148          else:
     149              self.testNames = list(self.defaultTest)
     150          self.createTests()
     151  
     152      def createTests(self, from_discovery=False, Loader=None):
     153          if self.testNamePatterns:
     154              self.testLoader.testNamePatterns = self.testNamePatterns
     155          if from_discovery:
     156              loader = self.testLoader if Loader is None else Loader()
     157              self.test = loader.discover(self.start, self.pattern, self.top)
     158          elif self.testNames is None:
     159              self.test = self.testLoader.loadTestsFromModule(self.module)
     160          else:
     161              self.test = self.testLoader.loadTestsFromNames(self.testNames,
     162                                                             self.module)
     163  
     164      def _initArgParsers(self):
     165          parent_parser = self._getParentArgParser()
     166          self._main_parser = self._getMainArgParser(parent_parser)
     167          self._discovery_parser = self._getDiscoveryArgParser(parent_parser)
     168  
     169      def _getParentArgParser(self):
     170          parser = argparse.ArgumentParser(add_help=False)
     171  
     172          parser.add_argument('-v', '--verbose', dest='verbosity',
     173                              action='store_const', const=2,
     174                              help='Verbose output')
     175          parser.add_argument('-q', '--quiet', dest='verbosity',
     176                              action='store_const', const=0,
     177                              help='Quiet output')
     178          parser.add_argument('--locals', dest='tb_locals',
     179                              action='store_true',
     180                              help='Show local variables in tracebacks')
     181          if self.failfast is None:
     182              parser.add_argument('-f', '--failfast', dest='failfast',
     183                                  action='store_true',
     184                                  help='Stop on first fail or error')
     185              self.failfast = False
     186          if self.catchbreak is None:
     187              parser.add_argument('-c', '--catch', dest='catchbreak',
     188                                  action='store_true',
     189                                  help='Catch Ctrl-C and display results so far')
     190              self.catchbreak = False
     191          if self.buffer is None:
     192              parser.add_argument('-b', '--buffer', dest='buffer',
     193                                  action='store_true',
     194                                  help='Buffer stdout and stderr during tests')
     195              self.buffer = False
     196          if self.testNamePatterns is None:
     197              parser.add_argument('-k', dest='testNamePatterns',
     198                                  action='append', type=_convert_select_pattern,
     199                                  help='Only run tests which match the given substring')
     200              self.testNamePatterns = []
     201  
     202          return parser
     203  
     204      def _getMainArgParser(self, parent):
     205          parser = argparse.ArgumentParser(parents=[parent])
     206          parser.prog = self.progName
     207          parser.print_help = self._print_help
     208  
     209          parser.add_argument('tests', nargs='*',
     210                              help='a list of any number of test modules, '
     211                              'classes and test methods.')
     212  
     213          return parser
     214  
     215      def _getDiscoveryArgParser(self, parent):
     216          parser = argparse.ArgumentParser(parents=[parent])
     217          parser.prog = '%s discover' % self.progName
     218          parser.epilog = ('For test discovery all test modules must be '
     219                           'importable from the top level directory of the '
     220                           'project.')
     221  
     222          parser.add_argument('-s', '--start-directory', dest='start',
     223                              help="Directory to start discovery ('.' default)")
     224          parser.add_argument('-p', '--pattern', dest='pattern',
     225                              help="Pattern to match tests ('test*.py' default)")
     226          parser.add_argument('-t', '--top-level-directory', dest='top',
     227                              help='Top level directory of project (defaults to '
     228                                   'start directory)')
     229          for arg in ('start', 'pattern', 'top'):
     230              parser.add_argument(arg, nargs='?',
     231                                  default=argparse.SUPPRESS,
     232                                  help=argparse.SUPPRESS)
     233  
     234          return parser
     235  
     236      def _do_discovery(self, argv, Loader=None):
     237          self.start = '.'
     238          self.pattern = 'test*.py'
     239          self.top = None
     240          if argv is not None:
     241              # handle command line args for test discovery
     242              if self._discovery_parser is None:
     243                  # for testing
     244                  self._initArgParsers()
     245              self._discovery_parser.parse_args(argv, self)
     246  
     247          self.createTests(from_discovery=True, Loader=Loader)
     248  
     249      def runTests(self):
     250          if self.catchbreak:
     251              installHandler()
     252          if self.testRunner is None:
     253              self.testRunner = runner.TextTestRunner
     254          if isinstance(self.testRunner, type):
     255              try:
     256                  try:
     257                      testRunner = self.testRunner(verbosity=self.verbosity,
     258                                                   failfast=self.failfast,
     259                                                   buffer=self.buffer,
     260                                                   warnings=self.warnings,
     261                                                   tb_locals=self.tb_locals)
     262                  except TypeError:
     263                      # didn't accept the tb_locals argument
     264                      testRunner = self.testRunner(verbosity=self.verbosity,
     265                                                   failfast=self.failfast,
     266                                                   buffer=self.buffer,
     267                                                   warnings=self.warnings)
     268              except TypeError:
     269                  # didn't accept the verbosity, buffer or failfast arguments
     270                  testRunner = self.testRunner()
     271          else:
     272              # it is assumed to be a TestRunner instance
     273              testRunner = self.testRunner
     274          self.result = testRunner.run(self.test)
     275          if self.exit:
     276              sys.exit(not self.result.wasSuccessful())
     277  
     278  main = TestProgram