17db96d56Sopenharmony_ci"""distutils.command.check 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciImplements the Distutils 'check' command. 47db96d56Sopenharmony_ci""" 57db96d56Sopenharmony_cifrom distutils.core import Command 67db96d56Sopenharmony_cifrom distutils.errors import DistutilsSetupError 77db96d56Sopenharmony_ci 87db96d56Sopenharmony_citry: 97db96d56Sopenharmony_ci # docutils is installed 107db96d56Sopenharmony_ci from docutils.utils import Reporter 117db96d56Sopenharmony_ci from docutils.parsers.rst import Parser 127db96d56Sopenharmony_ci from docutils import frontend 137db96d56Sopenharmony_ci from docutils import nodes 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci class SilentReporter(Reporter): 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ci def __init__(self, source, report_level, halt_level, stream=None, 187db96d56Sopenharmony_ci debug=0, encoding='ascii', error_handler='replace'): 197db96d56Sopenharmony_ci self.messages = [] 207db96d56Sopenharmony_ci Reporter.__init__(self, source, report_level, halt_level, stream, 217db96d56Sopenharmony_ci debug, encoding, error_handler) 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ci def system_message(self, level, message, *children, **kwargs): 247db96d56Sopenharmony_ci self.messages.append((level, message, children, kwargs)) 257db96d56Sopenharmony_ci return nodes.system_message(message, level=level, 267db96d56Sopenharmony_ci type=self.levels[level], 277db96d56Sopenharmony_ci *children, **kwargs) 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci HAS_DOCUTILS = True 307db96d56Sopenharmony_ciexcept Exception: 317db96d56Sopenharmony_ci # Catch all exceptions because exceptions besides ImportError probably 327db96d56Sopenharmony_ci # indicate that docutils is not ported to Py3k. 337db96d56Sopenharmony_ci HAS_DOCUTILS = False 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ciclass check(Command): 367db96d56Sopenharmony_ci """This command checks the meta-data of the package. 377db96d56Sopenharmony_ci """ 387db96d56Sopenharmony_ci description = ("perform some checks on the package") 397db96d56Sopenharmony_ci user_options = [('metadata', 'm', 'Verify meta-data'), 407db96d56Sopenharmony_ci ('restructuredtext', 'r', 417db96d56Sopenharmony_ci ('Checks if long string meta-data syntax ' 427db96d56Sopenharmony_ci 'are reStructuredText-compliant')), 437db96d56Sopenharmony_ci ('strict', 's', 447db96d56Sopenharmony_ci 'Will exit with an error if a check fails')] 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci boolean_options = ['metadata', 'restructuredtext', 'strict'] 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_ci def initialize_options(self): 497db96d56Sopenharmony_ci """Sets default values for options.""" 507db96d56Sopenharmony_ci self.restructuredtext = 0 517db96d56Sopenharmony_ci self.metadata = 1 527db96d56Sopenharmony_ci self.strict = 0 537db96d56Sopenharmony_ci self._warnings = 0 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci def finalize_options(self): 567db96d56Sopenharmony_ci pass 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci def warn(self, msg): 597db96d56Sopenharmony_ci """Counts the number of warnings that occurs.""" 607db96d56Sopenharmony_ci self._warnings += 1 617db96d56Sopenharmony_ci return Command.warn(self, msg) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci def run(self): 647db96d56Sopenharmony_ci """Runs the command.""" 657db96d56Sopenharmony_ci # perform the various tests 667db96d56Sopenharmony_ci if self.metadata: 677db96d56Sopenharmony_ci self.check_metadata() 687db96d56Sopenharmony_ci if self.restructuredtext: 697db96d56Sopenharmony_ci if HAS_DOCUTILS: 707db96d56Sopenharmony_ci self.check_restructuredtext() 717db96d56Sopenharmony_ci elif self.strict: 727db96d56Sopenharmony_ci raise DistutilsSetupError('The docutils package is needed.') 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci # let's raise an error in strict mode, if we have at least 757db96d56Sopenharmony_ci # one warning 767db96d56Sopenharmony_ci if self.strict and self._warnings > 0: 777db96d56Sopenharmony_ci raise DistutilsSetupError('Please correct your package.') 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci def check_metadata(self): 807db96d56Sopenharmony_ci """Ensures that all required elements of meta-data are supplied. 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci Required fields: 837db96d56Sopenharmony_ci name, version, URL 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci Recommended fields: 867db96d56Sopenharmony_ci (author and author_email) or (maintainer and maintainer_email) 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci Warns if any are missing. 897db96d56Sopenharmony_ci """ 907db96d56Sopenharmony_ci metadata = self.distribution.metadata 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci missing = [] 937db96d56Sopenharmony_ci for attr in ('name', 'version', 'url'): 947db96d56Sopenharmony_ci if not (hasattr(metadata, attr) and getattr(metadata, attr)): 957db96d56Sopenharmony_ci missing.append(attr) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci if missing: 987db96d56Sopenharmony_ci self.warn("missing required meta-data: %s" % ', '.join(missing)) 997db96d56Sopenharmony_ci if metadata.author: 1007db96d56Sopenharmony_ci if not metadata.author_email: 1017db96d56Sopenharmony_ci self.warn("missing meta-data: if 'author' supplied, " + 1027db96d56Sopenharmony_ci "'author_email' should be supplied too") 1037db96d56Sopenharmony_ci elif metadata.maintainer: 1047db96d56Sopenharmony_ci if not metadata.maintainer_email: 1057db96d56Sopenharmony_ci self.warn("missing meta-data: if 'maintainer' supplied, " + 1067db96d56Sopenharmony_ci "'maintainer_email' should be supplied too") 1077db96d56Sopenharmony_ci else: 1087db96d56Sopenharmony_ci self.warn("missing meta-data: either (author and author_email) " + 1097db96d56Sopenharmony_ci "or (maintainer and maintainer_email) " + 1107db96d56Sopenharmony_ci "should be supplied") 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci def check_restructuredtext(self): 1137db96d56Sopenharmony_ci """Checks if the long string fields are reST-compliant.""" 1147db96d56Sopenharmony_ci data = self.distribution.get_long_description() 1157db96d56Sopenharmony_ci for warning in self._check_rst_data(data): 1167db96d56Sopenharmony_ci line = warning[-1].get('line') 1177db96d56Sopenharmony_ci if line is None: 1187db96d56Sopenharmony_ci warning = warning[1] 1197db96d56Sopenharmony_ci else: 1207db96d56Sopenharmony_ci warning = '%s (line %s)' % (warning[1], line) 1217db96d56Sopenharmony_ci self.warn(warning) 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci def _check_rst_data(self, data): 1247db96d56Sopenharmony_ci """Returns warnings when the provided data doesn't compile.""" 1257db96d56Sopenharmony_ci # the include and csv_table directives need this to be a path 1267db96d56Sopenharmony_ci source_path = self.distribution.script_name or 'setup.py' 1277db96d56Sopenharmony_ci parser = Parser() 1287db96d56Sopenharmony_ci settings = frontend.OptionParser(components=(Parser,)).get_default_values() 1297db96d56Sopenharmony_ci settings.tab_width = 4 1307db96d56Sopenharmony_ci settings.pep_references = None 1317db96d56Sopenharmony_ci settings.rfc_references = None 1327db96d56Sopenharmony_ci reporter = SilentReporter(source_path, 1337db96d56Sopenharmony_ci settings.report_level, 1347db96d56Sopenharmony_ci settings.halt_level, 1357db96d56Sopenharmony_ci stream=settings.warning_stream, 1367db96d56Sopenharmony_ci debug=settings.debug, 1377db96d56Sopenharmony_ci encoding=settings.error_encoding, 1387db96d56Sopenharmony_ci error_handler=settings.error_encoding_error_handler) 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci document = nodes.document(settings, reporter, source=source_path) 1417db96d56Sopenharmony_ci document.note_source(source_path, -1) 1427db96d56Sopenharmony_ci try: 1437db96d56Sopenharmony_ci parser.parse(data, document) 1447db96d56Sopenharmony_ci except AttributeError as e: 1457db96d56Sopenharmony_ci reporter.messages.append( 1467db96d56Sopenharmony_ci (-1, 'Could not finish the parsing: %s.' % e, '', {})) 1477db96d56Sopenharmony_ci 1487db96d56Sopenharmony_ci return reporter.messages 149