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 @@ except ImportError:
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,