python (3.11.7)
       1  """distutils.command.check
       2  
       3  Implements the Distutils 'check' command.
       4  """
       5  import contextlib
       6  
       7  from distutils.core import Command
       8  from distutils.errors import DistutilsSetupError
       9  
      10  with contextlib.suppress(ImportError):
      11      import docutils.utils
      12      import docutils.parsers.rst
      13      import docutils.frontend
      14      import docutils.nodes
      15  
      16      class ESC[4;38;5;81mSilentReporter(ESC[4;38;5;149mdocutilsESC[4;38;5;149m.ESC[4;38;5;149mutilsESC[4;38;5;149m.ESC[4;38;5;149mReporter):
      17          def __init__(
      18              self,
      19              source,
      20              report_level,
      21              halt_level,
      22              stream=None,
      23              debug=0,
      24              encoding='ascii',
      25              error_handler='replace',
      26          ):
      27              self.messages = []
      28              super().__init__(
      29                  source, report_level, halt_level, stream, debug, encoding, error_handler
      30              )
      31  
      32          def system_message(self, level, message, *children, **kwargs):
      33              self.messages.append((level, message, children, kwargs))
      34              return docutils.nodes.system_message(
      35                  message, level=level, type=self.levels[level], *children, **kwargs
      36              )
      37  
      38  
      39  class ESC[4;38;5;81mcheck(ESC[4;38;5;149mCommand):
      40      """This command checks the meta-data of the package."""
      41  
      42      description = "perform some checks on the package"
      43      user_options = [
      44          ('metadata', 'm', 'Verify meta-data'),
      45          (
      46              'restructuredtext',
      47              'r',
      48              (
      49                  'Checks if long string meta-data syntax '
      50                  'are reStructuredText-compliant'
      51              ),
      52          ),
      53          ('strict', 's', 'Will exit with an error if a check fails'),
      54      ]
      55  
      56      boolean_options = ['metadata', 'restructuredtext', 'strict']
      57  
      58      def initialize_options(self):
      59          """Sets default values for options."""
      60          self.restructuredtext = 0
      61          self.metadata = 1
      62          self.strict = 0
      63          self._warnings = 0
      64  
      65      def finalize_options(self):
      66          pass
      67  
      68      def warn(self, msg):
      69          """Counts the number of warnings that occurs."""
      70          self._warnings += 1
      71          return Command.warn(self, msg)
      72  
      73      def run(self):
      74          """Runs the command."""
      75          # perform the various tests
      76          if self.metadata:
      77              self.check_metadata()
      78          if self.restructuredtext:
      79              if 'docutils' in globals():
      80                  try:
      81                      self.check_restructuredtext()
      82                  except TypeError as exc:
      83                      raise DistutilsSetupError(str(exc))
      84              elif self.strict:
      85                  raise DistutilsSetupError('The docutils package is needed.')
      86  
      87          # let's raise an error in strict mode, if we have at least
      88          # one warning
      89          if self.strict and self._warnings > 0:
      90              raise DistutilsSetupError('Please correct your package.')
      91  
      92      def check_metadata(self):
      93          """Ensures that all required elements of meta-data are supplied.
      94  
      95          Required fields:
      96              name, version
      97  
      98          Warns if any are missing.
      99          """
     100          metadata = self.distribution.metadata
     101  
     102          missing = []
     103          for attr in 'name', 'version':
     104              if not getattr(metadata, attr, None):
     105                  missing.append(attr)
     106  
     107          if missing:
     108              self.warn("missing required meta-data: %s" % ', '.join(missing))
     109  
     110      def check_restructuredtext(self):
     111          """Checks if the long string fields are reST-compliant."""
     112          data = self.distribution.get_long_description()
     113          for warning in self._check_rst_data(data):
     114              line = warning[-1].get('line')
     115              if line is None:
     116                  warning = warning[1]
     117              else:
     118                  warning = '{} (line {})'.format(warning[1], line)
     119              self.warn(warning)
     120  
     121      def _check_rst_data(self, data):
     122          """Returns warnings when the provided data doesn't compile."""
     123          # the include and csv_table directives need this to be a path
     124          source_path = self.distribution.script_name or 'setup.py'
     125          parser = docutils.parsers.rst.Parser()
     126          settings = docutils.frontend.OptionParser(
     127              components=(docutils.parsers.rst.Parser,)
     128          ).get_default_values()
     129          settings.tab_width = 4
     130          settings.pep_references = None
     131          settings.rfc_references = None
     132          reporter = SilentReporter(
     133              source_path,
     134              settings.report_level,
     135              settings.halt_level,
     136              stream=settings.warning_stream,
     137              debug=settings.debug,
     138              encoding=settings.error_encoding,
     139              error_handler=settings.error_encoding_error_handler,
     140          )
     141  
     142          document = docutils.nodes.document(settings, reporter, source=source_path)
     143          document.note_source(source_path, -1)
     144          try:
     145              parser.parse(data, document)
     146          except AttributeError as e:
     147              reporter.messages.append(
     148                  (-1, 'Could not finish the parsing: %s.' % e, '', {})
     149              )
     150  
     151          return reporter.messages