diff --git a/Doc/Makefile b/Doc/Makefile index 5b6a95813ab..f52087409a0 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -22,7 +22,7 @@ ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees $(PAPEROPT_$(PAPER)) -j auto \ $(SPHINXOPTS) $(SPHINXERRORHANDLING) . build/$(BUILDER) $(SOURCES) .PHONY: help build html htmlhelp latex text texinfo changes linkcheck \ - suspicious coverage doctest pydoc-topics htmlview clean dist check serve \ + coverage doctest pydoc-topics htmlview clean dist check serve \ autobuild-dev autobuild-stable venv help: @@ -42,7 +42,6 @@ help: @echo " doctest to run doctests in the documentation" @echo " pydoc-topics to regenerate the pydoc topics file" @echo " dist to create a \"dist\" directory with archived docs for download" - @echo " suspicious to check for suspicious markup in output text" @echo " check to run a check for frequent markup errors" build: @@ -110,18 +109,6 @@ linkcheck: "or in build/$(BUILDER)/output.txt"; \ false; } -suspicious: BUILDER = suspicious -suspicious: - @$(MAKE) build BUILDER=$(BUILDER) || { \ - echo "Suspicious check complete; look for any errors in the above output" \ - "or in build/$(BUILDER)/suspicious.csv. If all issues are false" \ - "positives, append that file to tools/susp-ignored.csv."; \ - false; } - @echo "⚠ make suspicious is deprecated and will be removed soon." - @echo "⚠ Use:" - @echo "⚠ make check" - @echo "⚠ instead." - coverage: BUILDER = coverage coverage: build @echo "Coverage finished; see c.txt and python.txt in build/coverage" diff --git a/Doc/README.rst b/Doc/README.rst index d67cad79916..a3bb5fa5445 100644 --- a/Doc/README.rst +++ b/Doc/README.rst @@ -93,9 +93,6 @@ Available make targets are: plain text documentation for the labels defined in ``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help. -* "suspicious", which checks the parsed markup for text that looks like - malformed and thus unconverted reST. - * "check", which checks for frequent markup errors. * "serve", which serves the build/html directory on port 8000. diff --git a/Doc/make.bat b/Doc/make.bat index 4f0b3c11f4f..87d8359ef11 100644 --- a/Doc/make.bat +++ b/Doc/make.bat @@ -109,7 +109,7 @@ echo.always available include: echo. echo. Provided by Sphinx: echo. html, htmlhelp, latex, text -echo. suspicious, linkcheck, changes, doctest +echo. linkcheck, changes, doctest echo. Provided by this script: echo. clean, check, htmlview echo. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 8c3aa47ad1c..3b9f7442f75 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -37,10 +37,6 @@ from sphinx.domains.python import PyClassmember as PyMethod from sphinx.domains.python import PyModulelevel as PyFunction -# Support for checking for suspicious markup - -import suspicious - ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s' GH_ISSUE_URI = 'https://github.com/python/cpython/issues/%s' @@ -686,7 +682,6 @@ def setup(app): app.add_directive('audit-event-table', AuditEventListDirective) app.add_directive('deprecated-removed', DeprecatedRemoved) app.add_builder(PydocTopicsBuilder) - app.add_builder(suspicious.CheckSuspiciousMarkupBuilder) app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command) app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)') diff --git a/Doc/tools/extensions/suspicious.py b/Doc/tools/extensions/suspicious.py deleted file mode 100644 index 2d581a8a6c3..00000000000 --- a/Doc/tools/extensions/suspicious.py +++ /dev/null @@ -1,251 +0,0 @@ -""" -Try to detect suspicious constructs, resembling markup -that has leaked into the final output. - -Suspicious lines are reported in a comma-separated-file, -``suspicious.csv``, located in the output directory. - -The file is utf-8 encoded, and each line contains four fields: - - * document name (normalized) - * line number in the source document - * problematic text - * complete line showing the problematic text in context - -It is common to find many false positives. To avoid reporting them -again and again, they may be added to the ``ignored.csv`` file -(located in the configuration directory). The file has the same -format as ``suspicious.csv`` with a few differences: - - - each line defines a rule; if the rule matches, the issue - is ignored. - - line number may be empty (that is, nothing between the - commas: ",,"). In this case, line numbers are ignored (the - rule matches anywhere in the file). - - the last field does not have to be a complete line; some - surrounding text (never more than a line) is enough for - context. - -Rules are processed sequentially. A rule matches when: - - * document names are the same - * problematic texts are the same - * line numbers are close to each other (5 lines up or down) - * the rule text is completely contained into the source line - -The simplest way to create the ignored.csv file is by copying -undesired entries from suspicious.csv (possibly trimming the last -field.) - -Copyright 2009 Gabriel A. Genellina - -""" - -import os -import re -import csv - -from docutils import nodes -from sphinx.builders import Builder -import sphinx.util - -detect_all = re.compile(r''' - ::(?=[^=])| # two :: (but NOT ::=) - :[a-zA-Z][a-zA-Z0-9]+| # :foo - `| # ` (seldom used by itself) - (? don't care - self.issue = issue # the markup fragment that triggered this rule - self.line = line # text of the container element (single line only) - self.used = False - - def __repr__(self): - return '{0.docname},,{0.issue},{0.line}'.format(self) - - - -class dialect(csv.excel): - """Our dialect: uses only linefeed as newline.""" - lineterminator = '\n' - - -class CheckSuspiciousMarkupBuilder(Builder): - """ - Checks for possibly invalid markup that may leak into the output. - """ - name = 'suspicious' - logger = sphinx.util.logging.getLogger("CheckSuspiciousMarkupBuilder") - - def init(self): - # create output file - self.log_file_name = os.path.join(self.outdir, 'suspicious.csv') - open(self.log_file_name, 'w').close() - # load database of previously ignored issues - self.load_rules(os.path.join(os.path.dirname(__file__), '..', - 'susp-ignored.csv')) - - def get_outdated_docs(self): - return self.env.found_docs - - def get_target_uri(self, docname, typ=None): - return '' - - def prepare_writing(self, docnames): - pass - - def write_doc(self, docname, doctree): - # set when any issue is encountered in this document - self.any_issue = False - self.docname = docname - visitor = SuspiciousVisitor(doctree, self) - doctree.walk(visitor) - - def finish(self): - unused_rules = [rule for rule in self.rules if not rule.used] - if unused_rules: - self.logger.warning( - 'Found %s/%s unused rules: %s' % ( - len(unused_rules), len(self.rules), - '\n'.join(repr(rule) for rule in unused_rules), - ) - ) - return - - def check_issue(self, line, lineno, issue): - if not self.is_ignored(line, lineno, issue): - self.report_issue(line, lineno, issue) - - def is_ignored(self, line, lineno, issue): - """Determine whether this issue should be ignored.""" - docname = self.docname - for rule in self.rules: - if rule.docname != docname: continue - if rule.issue != issue: continue - # Both lines must match *exactly*. This is rather strict, - # and probably should be improved. - # Doing fuzzy matches with levenshtein distance could work, - # but that means bringing other libraries... - # Ok, relax that requirement: just check if the rule fragment - # is contained in the document line - if rule.line not in line: continue - # Check both line numbers. If they're "near" - # this rule matches. (lineno=None means "don't care") - if (rule.lineno is not None) and \ - abs(rule.lineno - lineno) > 5: continue - # if it came this far, the rule matched - rule.used = True - return True - return False - - def report_issue(self, text, lineno, issue): - self.any_issue = True - self.write_log_entry(lineno, issue, text) - self.logger.warning('[%s:%d] "%s" found in "%-.120s"' % - (self.docname, lineno, issue, text)) - self.app.statuscode = 1 - - def write_log_entry(self, lineno, issue, text): - f = open(self.log_file_name, 'a') - writer = csv.writer(f, dialect) - writer.writerow([self.docname, lineno, issue, text.strip()]) - f.close() - - def load_rules(self, filename): - """Load database of previously ignored issues. - - A csv file, with exactly the same format as suspicious.csv - Fields: document name (normalized), line number, issue, surrounding text - """ - self.logger.info("loading ignore rules... ", nonl=1) - self.rules = rules = [] - try: - f = open(filename, 'r') - except IOError: - return - for i, row in enumerate(csv.reader(f)): - if len(row) != 4: - raise ValueError( - "wrong format in %s, line %d: %s" % (filename, i+1, row)) - docname, lineno, issue, text = row - if lineno: - lineno = int(lineno) - else: - lineno = None - rule = Rule(docname, lineno, issue, text) - rules.append(rule) - f.close() - self.logger.info('done, %d rules loaded' % len(self.rules)) - - -def get_lineno(node): - """Obtain line number information for a node.""" - lineno = None - while lineno is None and node: - node = node.parent - lineno = node.line - return lineno - - -def extract_line(text, index): - """text may be a multiline string; extract - only the line containing the given character index. - - >>> extract_line("abc\ndefgh\ni", 6) - >>> 'defgh' - >>> for i in (0, 2, 3, 4, 10): - ... print extract_line("abc\ndefgh\ni", i) - abc - abc - abc - defgh - defgh - i - """ - p = text.rfind('\n', 0, index) + 1 - q = text.find('\n', index) - if q < 0: - q = len(text) - return text[p:q] - - -class SuspiciousVisitor(nodes.GenericNodeVisitor): - - lastlineno = 0 - - def __init__(self, document, builder): - nodes.GenericNodeVisitor.__init__(self, document) - self.builder = builder - - def default_visit(self, node): - if isinstance(node, (nodes.Text, nodes.image)): # direct text containers - text = node.astext() - # lineno seems to go backwards sometimes (?) - self.lastlineno = lineno = max(get_lineno(node) or 0, self.lastlineno) - seen = set() # don't report the same issue more than only once per line - for match in detect_all(text): - issue = match.group() - line = extract_line(text, match.start()) - if (issue, line) not in seen: - self.builder.check_issue(line, lineno, issue) - seen.add((issue, line)) - - unknown_visit = default_visit - - def visit_document(self, node): - self.lastlineno = 0 - - def visit_comment(self, node): - # ignore comments -- too much false positives. - # (although doing this could miss some errors; - # there were two sections "commented-out" by mistake - # in the Python docs that would not be caught) - raise nodes.SkipNode diff --git a/Doc/tools/rstlint.py b/Doc/tools/rstlint.py deleted file mode 100644 index 4ea68ef3b03..00000000000 --- a/Doc/tools/rstlint.py +++ /dev/null @@ -1,408 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Check for stylistic and formal issues in .rst and .py -# files included in the documentation. -# -# 01/2009, Georg Brandl - -# TODO: - wrong versions in versionadded/changed -# - wrong markup after versionchanged directive - -import os -import re -import sys -import getopt -from string import ascii_letters -from os.path import join, splitext, abspath, exists -from collections import defaultdict - -directives = [ - # standard docutils ones - 'admonition', 'attention', 'caution', 'class', 'compound', 'container', - 'contents', 'csv-table', 'danger', 'date', 'default-role', 'epigraph', - 'error', 'figure', 'footer', 'header', 'highlights', 'hint', 'image', - 'important', 'include', 'line-block', 'list-table', 'meta', 'note', - 'parsed-literal', 'pull-quote', 'raw', 'replace', - 'restructuredtext-test-directive', 'role', 'rubric', 'sectnum', 'sidebar', - 'table', 'target-notes', 'tip', 'title', 'topic', 'unicode', 'warning', - # Sphinx and Python docs custom ones - 'acks', 'attribute', 'autoattribute', 'autoclass', 'autodata', - 'autoexception', 'autofunction', 'automethod', 'automodule', - 'availability', 'centered', 'cfunction', 'class', 'classmethod', 'cmacro', - 'cmdoption', 'cmember', 'code-block', 'confval', 'cssclass', 'ctype', - 'currentmodule', 'cvar', 'data', 'decorator', 'decoratormethod', - 'deprecated-removed', 'deprecated(?!-removed)', 'describe', 'directive', - 'doctest', 'envvar', 'event', 'exception', 'function', 'glossary', - 'highlight', 'highlightlang', 'impl-detail', 'index', 'literalinclude', - 'method', 'miscnews', 'module', 'moduleauthor', 'opcode', 'pdbcommand', - 'productionlist', 'program', 'role', 'sectionauthor', 'seealso', - 'sourcecode', 'staticmethod', 'tabularcolumns', 'testcode', 'testoutput', - 'testsetup', 'toctree', 'todo', 'todolist', 'versionadded', - 'versionchanged' -] - -roles = [ - "(? 81: - # don't complain about tables, links and function signatures - if line.lstrip()[0] not in '+|' and \ - 'http://' not in line and \ - not line.lstrip().startswith(('.. function', - '.. method', - '.. cfunction')): - yield lno+1, "line too long" - - -@checker('.html', severity=2, falsepositives=True) -def check_leaked_markup(fn, lines): - """Check HTML files for leaked reST markup; this only works if - the HTML files have been built. - """ - for lno, line in enumerate(lines): - if leaked_markup_re.search(line): - yield lno+1, 'possibly leaked markup: %r' % line - - -def hide_literal_blocks(lines): - """Tool to remove literal blocks from given lines. - - It yields empty lines in place of blocks, so line numbers are - still meaningful. - """ - in_block = False - for line in lines: - if line.endswith("::\n"): - in_block = True - elif in_block: - if line == "\n" or line.startswith(" "): - line = "\n" - else: - in_block = False - yield line - - -def type_of_explicit_markup(line): - if re.match(fr'\.\. {all_directives}::', line): - return 'directive' - if re.match(r'\.\. \[[0-9]+\] ', line): - return 'footnote' - if re.match(r'\.\. \[[^\]]+\] ', line): - return 'citation' - if re.match(r'\.\. _.*[^_]: ', line): - return 'target' - if re.match(r'\.\. \|[^\|]*\| ', line): - return 'substitution_definition' - return 'comment' - - -def hide_comments(lines): - """Tool to remove comments from given lines. - - It yields empty lines in place of comments, so line numbers are - still meaningful. - """ - in_multiline_comment = False - for line in lines: - if line == "..\n": - in_multiline_comment = True - elif in_multiline_comment: - if line == "\n" or line.startswith(" "): - line = "\n" - else: - in_multiline_comment = False - if line.startswith(".. ") and type_of_explicit_markup(line) == 'comment': - line = "\n" - yield line - - - -@checker(".rst", severity=2) -def check_missing_surrogate_space_on_plural(fn, lines): - r"""Check for missing 'backslash-space' between a code sample a letter. - - Good: ``Point``\ s - Bad: ``Point``s - """ - in_code_sample = False - check_next_one = False - for lno, line in enumerate(hide_comments(hide_literal_blocks(lines))): - tokens = line.split("``") - for token_no, token in enumerate(tokens): - if check_next_one: - if token[0] in ascii_letters: - yield lno + 1, f"Missing backslash-space between code sample and {token!r}." - check_next_one = False - if token_no == len(tokens) - 1: - continue - if in_code_sample: - check_next_one = True - in_code_sample = not in_code_sample - -def main(argv): - usage = '''\ -Usage: %s [-v] [-f] [-s sev] [-i path]* [path] - -Options: -v verbose (print all checked file names) - -f enable checkers that yield many false positives - -s sev only show problems with severity >= sev - -i path ignore subdir or file path -''' % argv[0] - try: - gopts, args = getopt.getopt(argv[1:], 'vfs:i:') - except getopt.GetoptError: - print(usage) - return 2 - - verbose = False - severity = 1 - ignore = [] - falsepos = False - for opt, val in gopts: - if opt == '-v': - verbose = True - elif opt == '-f': - falsepos = True - elif opt == '-s': - severity = int(val) - elif opt == '-i': - ignore.append(abspath(val)) - - if len(args) == 0: - path = '.' - elif len(args) == 1: - path = args[0] - else: - print(usage) - return 2 - - if not exists(path): - print('Error: path %s does not exist' % path) - return 2 - - count = defaultdict(int) - - print("""⚠ rstlint.py is no longer maintained here and will be removed -⚠ in a future release. -⚠ Please use https://pypi.org/p/sphinx-lint instead. -""") - - for root, dirs, files in os.walk(path): - # ignore subdirs in ignore list - if abspath(root) in ignore: - del dirs[:] - continue - - for fn in files: - fn = join(root, fn) - if fn[:2] == './': - fn = fn[2:] - - # ignore files in ignore list - if abspath(fn) in ignore: - continue - - ext = splitext(fn)[1] - checkerlist = checkers.get(ext, None) - if not checkerlist: - continue - - if verbose: - print('Checking %s...' % fn) - - try: - with open(fn, 'r', encoding='utf-8') as f: - lines = list(f) - except (IOError, OSError) as err: - print('%s: cannot open: %s' % (fn, err)) - count[4] += 1 - continue - - for checker in checkerlist: - if checker.falsepositives and not falsepos: - continue - csev = checker.severity - if csev >= severity: - for lno, msg in checker(fn, lines): - print('[%d] %s:%d: %s' % (csev, fn, lno, msg)) - count[csev] += 1 - if verbose: - print() - if not count: - if severity > 1: - print('No problems with severity >= %d found.' % severity) - else: - print('No problems found.') - else: - for severity in sorted(count): - number = count[severity] - print('%d problem%s with severity %d found.' % - (number, number > 1 and 's' or '', severity)) - return int(bool(count)) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv deleted file mode 100644 index 0dba0744b5f..00000000000 --- a/Doc/tools/susp-ignored.csv +++ /dev/null @@ -1,400 +0,0 @@ -c-api/arg,,:ref,"PyArg_ParseTuple(args, ""O|O:ref"", &object, &callback)" -c-api/list,,:high,list[low:high] -c-api/sequence,,:i2,del o[i1:i2] -c-api/sequence,,:i2,o[i1:i2] -c-api/tuple,,:high,p[low:high] -c-api/unicode,,:end,str[start:end] -c-api/unicode,,:start,unicode[start:start+length] -distutils/examples,,`,This is the description of the ``foobar`` package. -distutils/setupscript,,::, -extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))" -extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" -extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {" -extending/newtypes,,:call,"if (!PyArg_ParseTuple(args, ""sss:call"", &arg1, &arg2, &arg3)) {" -faq/programming,,:chr,">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" -faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y," -faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro," -faq/windows,,:d48eceb,"Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32" -howto/curses,,:black,"colors when it activates color mode. They are: 0:black, 1:red," -howto/curses,,:red,"colors when it activates color mode. They are: 0:black, 1:red," -howto/curses,,:green,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:yellow,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:blue,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:magenta,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:cyan,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/curses,,:white,"2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The" -howto/descriptor,,:root,"INFO:root" -howto/descriptor,,:Updating,"root:Updating" -howto/descriptor,,:Accessing,"root:Accessing" -howto/instrumentation,,::,python$target:::function-entry -howto/instrumentation,,:function,python$target:::function-entry -howto/instrumentation,,::,python$target:::function-return -howto/instrumentation,,:function,python$target:::function-return -howto/instrumentation,,:call,156641360502280 function-entry:call_stack.py:start:23 -howto/instrumentation,,:start,156641360502280 function-entry:call_stack.py:start:23 -howto/instrumentation,,:function,156641360518804 function-entry: call_stack.py:function_1:1 -howto/instrumentation,,:function,156641360532797 function-entry: call_stack.py:function_3:9 -howto/instrumentation,,:function,156641360546807 function-return: call_stack.py:function_3:10 -howto/instrumentation,,:function,156641360563367 function-return: call_stack.py:function_1:2 -howto/instrumentation,,:function,156641360578365 function-entry: call_stack.py:function_2:5 -howto/instrumentation,,:function,156641360591757 function-entry: call_stack.py:function_1:1 -howto/instrumentation,,:function,156641360605556 function-entry: call_stack.py:function_3:9 -howto/instrumentation,,:function,156641360617482 function-return: call_stack.py:function_3:10 -howto/instrumentation,,:function,156641360629814 function-return: call_stack.py:function_1:2 -howto/instrumentation,,:function,156641360642285 function-return: call_stack.py:function_2:6 -howto/instrumentation,,:function,156641360656770 function-entry: call_stack.py:function_3:9 -howto/instrumentation,,:function,156641360669707 function-return: call_stack.py:function_3:10 -howto/instrumentation,,:function,156641360687853 function-entry: call_stack.py:function_4:13 -howto/instrumentation,,:function,156641360700719 function-return: call_stack.py:function_4:14 -howto/instrumentation,,:function,156641360719640 function-entry: call_stack.py:function_5:18 -howto/instrumentation,,:function,156641360732567 function-return: call_stack.py:function_5:21 -howto/instrumentation,,:call,156641360747370 function-return:call_stack.py:start:28 -howto/instrumentation,,:start,156641360747370 function-return:call_stack.py:start:28 -howto/ipaddress,,:DB8,>>> ipaddress.ip_address('2001:DB8::1') -howto/ipaddress,,::,>>> ipaddress.ip_address('2001:DB8::1') -howto/ipaddress,,:db8,IPv6Address('2001:db8::1') -howto/ipaddress,,::,IPv6Address('2001:db8::1') -howto/ipaddress,,::,IPv6Address('::1') -howto/ipaddress,,:db8,>>> ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,::,>>> ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,:db8,IPv6Network('2001:db8::/96') -howto/ipaddress,,::,IPv6Network('2001:db8::/96') -howto/ipaddress,,:db8,IPv6Network('2001:db8::/128') -howto/ipaddress,,::,IPv6Network('2001:db8::/128') -howto/ipaddress,,:db8,IPv6Interface('2001:db8::1/96') -howto/ipaddress,,::,IPv6Interface('2001:db8::1/96') -howto/ipaddress,,:db8,>>> addr6 = ipaddress.ip_address('2001:db8::1') -howto/ipaddress,,::,>>> addr6 = ipaddress.ip_address('2001:db8::1') -howto/ipaddress,,:db8,>>> host6 = ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,::,>>> host6 = ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,:db8,>>> net6 = ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,::,>>> net6 = ipaddress.ip_network('2001:db8::0/96') -howto/ipaddress,,:ffff,IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::') -howto/ipaddress,,::,IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::') -howto/ipaddress,,::,IPv6Address('::ffff:ffff') -howto/ipaddress,,:ffff,IPv6Address('::ffff:ffff') -howto/ipaddress,,:db8,'2001:db8::/96' -howto/ipaddress,,::,'2001:db8::/96' -howto/ipaddress,,:db8,>>> ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,::,>>> ipaddress.ip_interface('2001:db8::1/96') -howto/ipaddress,,:db8,'2001:db8::1' -howto/ipaddress,,::,'2001:db8::1' -howto/ipaddress,,:db8,IPv6Address('2001:db8::ffff:ffff') -howto/ipaddress,,::,IPv6Address('2001:db8::ffff:ffff') -howto/ipaddress,,:ffff,IPv6Address('2001:db8::ffff:ffff') -howto/logging,,:And,"WARNING:And this, too" -howto/logging,,:And,"WARNING:root:And this, too" -howto/logging,,:And,"ERROR:root:And non-ASCII stuff, too, like " -howto/logging,,:Doing,INFO:root:Doing something -howto/logging,,:Finished,INFO:root:Finished -howto/logging,,:logger,severity:logger name:message -howto/logging,,:Look,WARNING:root:Look before you leap! -howto/logging,,:message,severity:logger name:message -howto/logging,,:root,DEBUG:root:This message should go to the log file -howto/logging,,:root,INFO:root:Doing something -howto/logging,,:root,INFO:root:Finished -howto/logging,,:root,INFO:root:So should this -howto/logging,,:root,"ERROR:root:And non-ASCII stuff, too, like " -howto/logging,,:root,INFO:root:Started -howto/logging,,:root,"WARNING:root:And this, too" -howto/logging,,:root,WARNING:root:Look before you leap! -howto/logging,,:root,WARNING:root:Watch out! -howto/logging,,:So,INFO:root:So should this -howto/logging,,:So,INFO:So should this -howto/logging,,:Started,INFO:root:Started -howto/logging,,:This,DEBUG:root:This message should go to the log file -howto/logging,,:This,DEBUG:This message should appear on the console -howto/logging,,:Watch,WARNING:root:Watch out! -howto/pyporting,,::,Programming Language :: Python :: 2 -howto/pyporting,,::,Programming Language :: Python :: 3 -howto/regex,,::, -howto/regex,,:foo,(?:foo) -howto/urllib2,,:password,"""joe:password@example.com""" -library/__main__,,`, -library/ast,,:upper,lower:upper -library/ast,,:step,lower:upper:step -library/audioop,,:ipos,"# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)]," -library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds -library/configparser,,:option,${section:option} -library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/ -library/datetime,,:MM, -library/datetime,,:SS, -library/decimal,,:optional,"trailneg:optional trailing minus indicator" -library/difflib,,:ahi,a[alo:ahi] -library/difflib,,:bhi,b[blo:bhi] -library/difflib,,:i1, -library/difflib,,:i2, -library/difflib,,:j2, -library/doctest,,`,``factorial`` from the ``example`` module: -library/doctest,,`,The ``example`` module -library/doctest,,`,Using ``factorial`` -library/exceptions,,:err,err.object[err.start:err.end] -library/functions,,:step,a[start:stop:step] -library/functions,,:stop,"a[start:stop, i]" -library/functions,,:stop,a[start:stop:step] -library/hashlib,,:LEAF,"h00 = blake2b(buf[0:LEAF_SIZE], fanout=FANOUT, depth=DEPTH," -library/http.client,,:port,host:port -library/http.cookies,,`,!#$%&'*+-.^_`|~: -library/imaplib,,:MM,"""DD-Mmm-YYYY HH:MM:SS" -library/imaplib,,:SS,"""DD-Mmm-YYYY HH:MM:SS" -library/inspect,,:int,">>> def foo(a, *, b:int, **kwargs):" -library/inspect,,:int,"'(a, *, b:int, **kwargs)'" -library/inspect,,:int,'b:int' -library/ipaddress,,:db8,>>> ipaddress.ip_address('2001:db8::') -library/ipaddress,,::,>>> ipaddress.ip_address('2001:db8::') -library/ipaddress,,:db8,IPv6Address('2001:db8::') -library/ipaddress,,::,IPv6Address('2001:db8::') -library/ipaddress,,:db8,>>> ipaddress.IPv6Address('2001:db8::1000') -library/ipaddress,,::,>>> ipaddress.IPv6Address('2001:db8::1000') -library/ipaddress,,:db8,'2001:db8::1000' -library/ipaddress,,::,'2001:db8::1000' -library/ipaddress,,:db8,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" -library/ipaddress,,::,">>> f'{ipaddress.IPv6Address(""2001:db8::1000""):s}'" -library/ipaddress,,::,IPv6Address('ff02::5678%1') -library/ipaddress,,::,fe80::1234 -library/ipaddress,,:db8,">>> ipaddress.ip_address(""2001:db8::1"").reverse_pointer" -library/ipaddress,,::,">>> ipaddress.ip_address(""2001:db8::1"").reverse_pointer" -library/ipaddress,,::,"""::abc:7:def""" -library/ipaddress,,:def,"""::abc:7:def""" -library/ipaddress,,::,::FFFF/96 -library/ipaddress,,::,2002::/16 -library/ipaddress,,::,2001::/32 -library/ipaddress,,::,>>> str(ipaddress.IPv6Address('::1')) -library/ipaddress,,::,'::1' -library/ipaddress,,:ff00,ffff:ff00:: -library/ipaddress,,:db00,2001:db00::0/24 -library/ipaddress,,::,2001:db00::0/24 -library/ipaddress,,:db00,2001:db00::0/ffff:ff00:: -library/ipaddress,,::,2001:db00::0/ffff:ff00:: -library/itertools,,:step,elements from seq[start:stop:step] -library/itertools,,::,kernel = tuple(kernel)[::-1] -library/itertools,,:stop,elements from seq[start:stop:step] -library/logging.handlers,,:port,host:port -library/logging,,:root,WARNING:root:Watch out! -library/logging,,:Watch,WARNING:root:Watch out! -library/mmap,,:i2,obj[i1:i2] -library/multiprocessing,,`,# Add more tasks using `put()` -library/multiprocessing,,:queue,">>> QueueManager.register('get_queue', callable=lambda:queue)" -library/multiprocessing,,`,# register the Foo class; make `f()` and `g()` accessible via proxy -library/multiprocessing,,`,# register the Foo class; make `g()` and `_h()` accessible via proxy -library/multiprocessing,,`,# register the generator function baz; use `GeneratorProxy` to make proxies -library/nntplib,,:bytes,:bytes -library/nntplib,,:lines,:lines -library/optparse,,:len,"del parser.rargs[:len(value)]" -library/os.path,,:foo,c:foo -library/pathlib,,:bar,">>> PureWindowsPath('c:/Windows', 'd:bar')" -library/pathlib,,:bar,PureWindowsPath('d:bar') -library/pathlib,,:Program,>>> PureWindowsPath('c:Program Files/').root -library/pathlib,,:Program,>>> PureWindowsPath('c:Program Files/').anchor -library/pdb,,:lineno,filename:lineno -library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")" -library/posix,,`,"CFLAGS=""`getconf LFS_CFLAGS`"" OPT=""-g -O2 $CFLAGS""" -library/pprint,,::,"'Programming Language :: Python :: 2.6'," -library/pprint,,::,"'Programming Language :: Python :: 2.7'," -library/pprint,,::,"'classifiers': ['Development Status :: 3 - Alpha'," -library/pprint,,::,"'Intended Audience :: Developers'," -library/pprint,,::,"'License :: OSI Approved :: MIT License'," -library/pprint,,::,"'Programming Language :: Python :: 2'," -library/pprint,,::,"'Programming Language :: Python :: 3'," -library/pprint,,::,"'Programming Language :: Python :: 3.2'," -library/pprint,,::,"'Programming Language :: Python :: 3.3'," -library/pprint,,::,"'Programming Language :: Python :: 3.4'," -library/pprint,,::,"'Topic :: Software Development :: Build Tools']," -library/profile,,:lineno,filename:lineno(function) -library/pyexpat,,:elem1, -library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" -library/random,,:len,new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):]) -library/readline,,:bind,"python:bind -v" -library/readline,,:bind,"python:bind ^I rl_complete" -library/smtplib,,:port,method must support that as well as a regular host:port -library/socket,,::,'5aef:2b::8' -library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" -library/socket,,:len,fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) -library/sqlite3,,:year,"cur.execute(""select * from lang where first_appeared=:year"", {""year"": 1972})" -library/sqlite3,,:memory, -library/sqlite3,,:template,"con = sqlite3.connect(""file:template.db?mode=ro"", uri=True)" -library/sqlite3,,:nosuchdb,"con = sqlite3.connect(""file:nosuchdb.db?mode=rw"", uri=True)" -library/sqlite3,,:mem1,"con1 = sqlite3.connect(""file:mem1?mode=memory&cache=shared"", uri=True)" -library/sqlite3,,:mem1,"con2 = sqlite3.connect(""file:mem1?mode=memory&cache=shared"", uri=True)" -library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" -library/ssl,,:My,"Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc." -library/ssl,,:myserver,"Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com" -library/ssl,,:MyState,State or Province Name (full name) [Some-State]:MyState -library/ssl,,:ops,Email Address []:ops@myserver.mygroup.myorganization.com -library/ssl,,:Some,"Locality Name (eg, city) []:Some City" -library/ssl,,:US,Country Name (2 letter code) [AU]:US -library/stdtypes,,:end,s[start:end] -library/stdtypes,,::,>>> hash(v[::-2]) == hash(b'abcefg'[::-2]) -library/stdtypes,,:len,s[len(s):len(s)] -library/stdtypes,,::,>>> y = m[::2] -library/stdtypes,,::,>>> z = y[::-2] -library/string,,`,"!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~" -library/tarfile,,:bz2, -library/tarfile,,:compression,filemode[:compression] -library/tarfile,,:gz, -library/tarfile,,:xz,'a:xz' -library/tarfile,,:xz,'r:xz' -library/tarfile,,:xz,'w:xz' -library/time,,:mm, -library/time,,:ss, -library/tracemalloc,,:limit,"for index, stat in enumerate(top_stats[:limit], 1):" -library/turtle,,::,Example:: -library/unittest,,:foo,"self.assertEqual(cm.output, ['INFO:foo:first message'," -library/unittest,,:first,"self.assertEqual(cm.output, ['INFO:foo:first message'," -library/unittest,,:foo,'ERROR:foo.bar:second message']) -library/unittest,,:second,'ERROR:foo.bar:second message']) -library/urllib.request,,:close,Connection:close -library/urllib.request,,:port,:port -library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" -library/urllib.request,,:password,"""joe:password@python.org""" -library/urllib.parse,,:scheme, -library/urllib.parse,,:scheme,URL:scheme://host/path -library/uuid,,:uuid,urn:uuid:12345678-1234-5678-1234-567812345678 -library/venv,,:param,":param nodist: If true, setuptools and pip are not installed into the" -library/venv,,:param,":param progress: If setuptools or pip are installed, the progress of the" -library/venv,,:param,":param nopip: If true, pip is not installed into the created" -library/venv,,:param,:param context: The information for the virtual environment -library/xmlrpc.client,,:nil,ex:nil -library/xmlrpc.client,,:pass,http://user:pass@host:port/path -library/xmlrpc.client,,:pass,user:pass -library/xmlrpc.client,,:port,http://user:pass@host:port/path -license,,`,"``Software''), to deal in the Software without restriction, including" -license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," -license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND -license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY -license,,`,THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND -license,,:zooko,mailto:zooko@zooko.com -reference/expressions,,:index,x[index:index] -reference/lexical_analysis,,`,$ ? ` -reference/lexical_analysis,,:fileencoding,# vim:fileencoding= -tutorial/datastructures,,:value,It is also possible to delete a key:value -tutorial/datastructures,,:value,key:value pairs within the braces adds initial key:value pairs -tutorial/stdlib2,,:config,"logging.warning('Warning:config file %s not found', 'server.conf')" -tutorial/stdlib2,,:config,WARNING:root:Warning:config file server.conf not found -tutorial/stdlib2,,:Critical,CRITICAL:root:Critical error -- shutting down -tutorial/stdlib2,,:Error,ERROR:root:Error occurred -tutorial/stdlib2,,:root,CRITICAL:root:Critical error -- shutting down -tutorial/stdlib2,,:root,ERROR:root:Error occurred -tutorial/stdlib2,,:root,WARNING:root:Warning:config file server.conf not found -tutorial/stdlib2,,:start,extra = data[start:start+extra_size] -tutorial/stdlib2,,:start,"fields = struct.unpack('>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') -whatsnew/2.7,,:Sunday,'2009:4:Sunday' -whatsnew/2.7,,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,,::,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:directory,${buildout:directory}/downloads/dist -whatsnew/3.2,,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" -whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" -whatsnew/3.2,,:location,zope9-location = ${zope9:location} -whatsnew/3.2,,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf -library/re,,`,!#$%&'*+-.^_`|~: -library/re,,`,!\#\$%\&'\*\+\-\.\^_`\|\~: -library/tarfile,,:xz,'x:xz' -library/warnings,,:message,action:message:category:module:line -library/warnings,,:category,action:message:category:module:line -library/warnings,,:module,action:message:category:module:line -library/warnings,,:line,action:message:category:module:line -library/warnings,,::,error::ResourceWarning -library/warnings,,::,default::DeprecationWarning -library/warnings,,::,default:::mymodule -library/warnings,,:mymodule,default:::mymodule -library/warnings,,::,error:::mymodule -library/warnings,,:mymodule,error:::mymodule -library/warnings,,::,ignore::DeprecationWarning -library/warnings,,::,ignore::PendingDeprecationWarning -library/warnings,,::,ignore::ImportWarning -library/warnings,,::,ignore::ResourceWarning -library/xml.etree.elementtree,,:sometag,prefix:sometag -library/xml.etree.elementtree,,:fictional,"Lancelot -library/xml.etree.elementtree,,:character,Archie Leach -library/xml.etree.elementtree,,:character,Sir Robin -library/xml.etree.elementtree,,:character,Gunther -library/xml.etree.elementtree,,:character,Commander Clement -library/xml.etree.elementtree,,:actor,"for actor in root.findall('real_person:actor', ns):" -library/xml.etree.elementtree,,:name,"name = actor.find('real_person:name', ns)" -library/xml.etree.elementtree,,:character,"for char in actor.findall('role:character', ns):" -library/xml.etree.elementtree,,:xi, -library/xml.etree.elementtree,,:include, -library/xml.etree.elementtree,,:include, Copyright (c) . -library/zipapp,,:main,"$ python -m zipapp myapp -m ""myapp:main""" -library/zipapp,,:fn,"pkg.mod:fn" -library/zipapp,,:callable,"pkg.module:callable" -library/stdtypes,,::,>>> m[::2].tolist() -whatsnew/3.5,,:root,'WARNING:root:warning\n' -whatsnew/3.5,,:warning,'WARNING:root:warning\n' -whatsnew/3.5,,::,>>> addr6 = ipaddress.IPv6Address('::1') -whatsnew/3.5,,:root,ERROR:root:exception -whatsnew/3.5,,:exception,ERROR:root:exception -whatsnew/changelog,,`,'`' -whatsnew/changelog,,:end,str[start:end] -library/binascii,,`,'`' -library/uu,,`,'`' -whatsnew/3.7,,`,'`' -whatsnew/3.7,,::,error::BytesWarning -whatsnew/changelog,,::,error::BytesWarning -whatsnew/changelog,,::,default::BytesWarning -whatsnew/changelog,,::,default::DeprecationWarning -library/importlib.metadata,,:main,"EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')" -library/importlib.metadata,,`,loading the metadata for packages for the indicated ``context``. -library/re,,`,"`" -library/typing,,`,# Type of ``val`` is narrowed to ``str`` -library/typing,,`,"# Else, type of ``val`` is narrowed to ``float``." -library/typing,,`,# Type of ``val`` is narrowed to ``list[str]``. -library/typing,,`,# Type of ``val`` remains as ``list[object]``. -library/tkinter,,::,ttk::frame .frm -padding 10 -library/tkinter,,::,"grid [ttk::label .frm.lbl -text ""Hello World!""] -column 0 -row 0" -library/tkinter,,::,"grid [ttk::button .frm.btn -text ""Quit"" -command ""destroy .""] -column 1 -row 0" -library/tkinter,,::,ttk::frame -library/tkinter,,::,ttk::button -library/tkinter,,::,ttk::widget -reference/compound_stmts,,:exc,subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except -reference/compound_stmts,,`,subclass of :exc:`BaseExceptionGroup`. It is not possible to mix except -reference/compound_stmts,,:keyword,"and except* in the same :keyword:`try`. :keyword:`break`," -reference/compound_stmts,,`,"and except* in the same :keyword:`try`. :keyword:`break`," -reference/compound_stmts,,:keyword,:keyword:`continue` and :keyword:`return` cannot appear in an except* -reference/compound_stmts,,`,:keyword:`continue` and :keyword:`return` cannot appear in an except* -whatsnew/changelog,,:CON,": os.path.abspath(“C:CON”) is now fixed to return “\.CON”, not" -whatsnew/changelog,,::,Lib/email/mime/nonmultipart.py::MIMENonMultipart -library/typing,,`,"assert_type(name, str) # OK, inferred type of `name` is `str`" -library/typing,,`,# after which we hope the inferred type will be `int` -whatsnew/changelog,,:company,-V:company/tag -library/typing,,`,# are located in the `typing_extensions` backports package. -library/dis,490,:TOS,TOS = TOS2[TOS1:TOS] -library/dis,497,:TOS,TOS2[TOS1:TOS] = TOS3 diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f8122ed1dc4..ebc490691e3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -468,6 +468,11 @@ Removed * ``importlib.util.set_package`` has been removed. (Contributed by Brett Cannon in :gh:`65961`.) +* Removed the ``suspicious`` rule from the documentation Makefile, and + removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint + `_. + (Contributed by Julien Palard in :gh:`98179`.) + Porting to Python 3.12 ====================== diff --git a/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst b/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst new file mode 100644 index 00000000000..de7b0921671 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-10-11-09-40-50.gh-issue-86404.dEAb8W.rst @@ -0,0 +1,3 @@ +Deprecated tools ``make suspicious`` and ``rstlint.py`` are now removed. +They have been replaced by `spinx-lint +`_.