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