mirror of https://github.com/python/cpython
gh-86404: Doc: Drop now unused make suspicious and rstlint. (GH-98179)
They have been replaced by [sphinx-lint](https://github.com/sphinx-contrib/sphinx-lint).
This commit is contained in:
parent
ad8e297b72
commit
4067c6d7fe
15
Doc/Makefile
15
Doc/Makefile
|
@ -22,7 +22,7 @@ ALLSPHINXOPTS = -b $(BUILDER) -d build/doctrees $(PAPEROPT_$(PAPER)) -j auto \
|
||||||
$(SPHINXOPTS) $(SPHINXERRORHANDLING) . build/$(BUILDER) $(SOURCES)
|
$(SPHINXOPTS) $(SPHINXERRORHANDLING) . build/$(BUILDER) $(SOURCES)
|
||||||
|
|
||||||
.PHONY: help build html htmlhelp latex text texinfo changes linkcheck \
|
.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
|
autobuild-dev autobuild-stable venv
|
||||||
|
|
||||||
help:
|
help:
|
||||||
|
@ -42,7 +42,6 @@ help:
|
||||||
@echo " doctest to run doctests in the documentation"
|
@echo " doctest to run doctests in the documentation"
|
||||||
@echo " pydoc-topics to regenerate the pydoc topics file"
|
@echo " pydoc-topics to regenerate the pydoc topics file"
|
||||||
@echo " dist to create a \"dist\" directory with archived docs for download"
|
@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"
|
@echo " check to run a check for frequent markup errors"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
@ -110,18 +109,6 @@ linkcheck:
|
||||||
"or in build/$(BUILDER)/output.txt"; \
|
"or in build/$(BUILDER)/output.txt"; \
|
||||||
false; }
|
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: BUILDER = coverage
|
||||||
coverage: build
|
coverage: build
|
||||||
@echo "Coverage finished; see c.txt and python.txt in build/coverage"
|
@echo "Coverage finished; see c.txt and python.txt in build/coverage"
|
||||||
|
|
|
@ -93,9 +93,6 @@ Available make targets are:
|
||||||
plain text documentation for the labels defined in
|
plain text documentation for the labels defined in
|
||||||
``tools/pyspecific.py`` -- pydoc needs these to show topic and keyword help.
|
``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.
|
* "check", which checks for frequent markup errors.
|
||||||
|
|
||||||
* "serve", which serves the build/html directory on port 8000.
|
* "serve", which serves the build/html directory on port 8000.
|
||||||
|
|
|
@ -109,7 +109,7 @@ echo.always available include:
|
||||||
echo.
|
echo.
|
||||||
echo. Provided by Sphinx:
|
echo. Provided by Sphinx:
|
||||||
echo. html, htmlhelp, latex, text
|
echo. html, htmlhelp, latex, text
|
||||||
echo. suspicious, linkcheck, changes, doctest
|
echo. linkcheck, changes, doctest
|
||||||
echo. Provided by this script:
|
echo. Provided by this script:
|
||||||
echo. clean, check, htmlview
|
echo. clean, check, htmlview
|
||||||
echo.
|
echo.
|
||||||
|
|
|
@ -37,10 +37,6 @@ except ImportError:
|
||||||
from sphinx.domains.python import PyClassmember as PyMethod
|
from sphinx.domains.python import PyClassmember as PyMethod
|
||||||
from sphinx.domains.python import PyModulelevel as PyFunction
|
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'
|
ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s'
|
||||||
GH_ISSUE_URI = 'https://github.com/python/cpython/issues/%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('audit-event-table', AuditEventListDirective)
|
||||||
app.add_directive('deprecated-removed', DeprecatedRemoved)
|
app.add_directive('deprecated-removed', DeprecatedRemoved)
|
||||||
app.add_builder(PydocTopicsBuilder)
|
app.add_builder(PydocTopicsBuilder)
|
||||||
app.add_builder(suspicious.CheckSuspiciousMarkupBuilder)
|
|
||||||
app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
|
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('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command)
|
||||||
app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
|
app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
|
||||||
|
|
|
@ -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)
|
|
||||||
(?<!\.)\.\.[ \t]*\w+: # .. foo: (but NOT ... else:)
|
|
||||||
''', re.VERBOSE).finditer
|
|
||||||
|
|
||||||
|
|
||||||
class Rule:
|
|
||||||
def __init__(self, docname, lineno, issue, line):
|
|
||||||
"""A rule for ignoring issues"""
|
|
||||||
self.docname = docname # document to which this rule applies
|
|
||||||
self.lineno = lineno # line number in the original source;
|
|
||||||
# this rule matches only near that.
|
|
||||||
# None -> 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
|
|
|
@ -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 = [
|
|
||||||
"(?<!py):class:",
|
|
||||||
"(?<!:c|py):func:",
|
|
||||||
"(?<!py):meth:",
|
|
||||||
"(?<!:py):mod:",
|
|
||||||
":exc:",
|
|
||||||
":issue:",
|
|
||||||
":attr:",
|
|
||||||
":c:func:",
|
|
||||||
":ref:",
|
|
||||||
":const:",
|
|
||||||
":term:",
|
|
||||||
"(?<!:c|py):data:",
|
|
||||||
":keyword:",
|
|
||||||
":file:",
|
|
||||||
":pep:",
|
|
||||||
":c:type:",
|
|
||||||
":c:member:",
|
|
||||||
":option:",
|
|
||||||
":rfc:",
|
|
||||||
":envvar:",
|
|
||||||
":c:data:",
|
|
||||||
":source:",
|
|
||||||
":mailheader:",
|
|
||||||
":program:",
|
|
||||||
":c:macro:",
|
|
||||||
":dfn:",
|
|
||||||
":kbd:",
|
|
||||||
":command:",
|
|
||||||
":mimetype:",
|
|
||||||
":opcode:",
|
|
||||||
":manpage:",
|
|
||||||
":py:data:",
|
|
||||||
":RFC:",
|
|
||||||
":pdbcmd:",
|
|
||||||
":abbr:",
|
|
||||||
":samp:",
|
|
||||||
":token:",
|
|
||||||
":PEP:",
|
|
||||||
":sup:",
|
|
||||||
":py:class:",
|
|
||||||
":menuselection:",
|
|
||||||
":doc:",
|
|
||||||
":sub:",
|
|
||||||
":py:meth:",
|
|
||||||
":newsgroup:",
|
|
||||||
":code:",
|
|
||||||
":py:func:",
|
|
||||||
":makevar:",
|
|
||||||
":guilabel:",
|
|
||||||
":title-reference:",
|
|
||||||
":py:mod:",
|
|
||||||
":download:",
|
|
||||||
":2to3fixer:",
|
|
||||||
]
|
|
||||||
|
|
||||||
all_directives = "(" + "|".join(directives) + ")"
|
|
||||||
all_roles = "(" + "|".join(roles) + ")"
|
|
||||||
|
|
||||||
# Find comments that looks like a directive, like:
|
|
||||||
# .. versionchanged 3.6
|
|
||||||
# or
|
|
||||||
# .. versionchanged: 3.6
|
|
||||||
# as it should be:
|
|
||||||
# .. versionchanged:: 3.6
|
|
||||||
seems_directive_re = re.compile(r"(?<!\.)\.\. %s([^a-z:]|:(?!:))" % all_directives)
|
|
||||||
|
|
||||||
# Find directive prefixed with three dots instead of two, like:
|
|
||||||
# ... versionchanged:: 3.6
|
|
||||||
# instead of:
|
|
||||||
# .. versionchanged:: 3.6
|
|
||||||
three_dot_directive_re = re.compile(r"\.\.\. %s::" % all_directives)
|
|
||||||
|
|
||||||
# Find role used with double backticks instead of simple backticks like:
|
|
||||||
# :const:``None``
|
|
||||||
# instead of:
|
|
||||||
# :const:`None`
|
|
||||||
double_backtick_role = re.compile(r"(?<!``)%s``" % all_roles)
|
|
||||||
|
|
||||||
|
|
||||||
# Find role used with no backticks instead of simple backticks like:
|
|
||||||
# :const:None
|
|
||||||
# instead of:
|
|
||||||
# :const:`None`
|
|
||||||
role_with_no_backticks = re.compile(r"%s[^` ]" % all_roles)
|
|
||||||
|
|
||||||
# Find role glued with another word like:
|
|
||||||
# the:c:func:`PyThreadState_LeaveTracing` function.
|
|
||||||
# instead of:
|
|
||||||
# the :c:func:`PyThreadState_LeaveTracing` function.
|
|
||||||
role_glued_with_word = re.compile(r"[a-zA-Z]%s" % all_roles)
|
|
||||||
|
|
||||||
default_role_re = re.compile(r"(^| )`\w([^`]*?\w)?`($| )")
|
|
||||||
leaked_markup_re = re.compile(r"[a-z]::\s|`|\.\.\s*\w+:")
|
|
||||||
|
|
||||||
|
|
||||||
checkers = {}
|
|
||||||
|
|
||||||
checker_props = {'severity': 1, 'falsepositives': False}
|
|
||||||
|
|
||||||
|
|
||||||
def checker(*suffixes, **kwds):
|
|
||||||
"""Decorator to register a function as a checker."""
|
|
||||||
def deco(func):
|
|
||||||
for suffix in suffixes:
|
|
||||||
checkers.setdefault(suffix, []).append(func)
|
|
||||||
for prop in checker_props:
|
|
||||||
setattr(func, prop, kwds.get(prop, checker_props[prop]))
|
|
||||||
return func
|
|
||||||
return deco
|
|
||||||
|
|
||||||
|
|
||||||
@checker('.py', severity=4)
|
|
||||||
def check_syntax(fn, lines):
|
|
||||||
"""Check Python examples for valid syntax."""
|
|
||||||
code = ''.join(lines)
|
|
||||||
if '\r' in code:
|
|
||||||
if os.name != 'nt':
|
|
||||||
yield 0, '\\r in code file'
|
|
||||||
code = code.replace('\r', '')
|
|
||||||
try:
|
|
||||||
compile(code, fn, 'exec')
|
|
||||||
except SyntaxError as err:
|
|
||||||
yield err.lineno, 'not compilable: %s' % err
|
|
||||||
|
|
||||||
|
|
||||||
@checker('.rst', severity=2)
|
|
||||||
def check_suspicious_constructs(fn, lines):
|
|
||||||
"""Check for suspicious reST constructs."""
|
|
||||||
inprod = False
|
|
||||||
for lno, line in enumerate(lines, start=1):
|
|
||||||
if seems_directive_re.search(line):
|
|
||||||
yield lno, "comment seems to be intended as a directive"
|
|
||||||
if three_dot_directive_re.search(line):
|
|
||||||
yield lno, "directive should start with two dots, not three."
|
|
||||||
if double_backtick_role.search(line):
|
|
||||||
yield lno, "role use a single backtick, double backtick found."
|
|
||||||
if role_with_no_backticks.search(line):
|
|
||||||
yield lno, "role use a single backtick, no backtick found."
|
|
||||||
if role_glued_with_word.search(line):
|
|
||||||
yield lno, "missing space before role"
|
|
||||||
if ".. productionlist::" in line:
|
|
||||||
inprod = True
|
|
||||||
elif not inprod and default_role_re.search(line):
|
|
||||||
yield lno, "default role used"
|
|
||||||
elif inprod and not line.strip():
|
|
||||||
inprod = False
|
|
||||||
|
|
||||||
|
|
||||||
@checker('.py', '.rst')
|
|
||||||
def check_whitespace(fn, lines):
|
|
||||||
"""Check for whitespace and line length issues."""
|
|
||||||
for lno, line in enumerate(lines):
|
|
||||||
if '\r' in line:
|
|
||||||
yield lno+1, '\\r in line'
|
|
||||||
if '\t' in line:
|
|
||||||
yield lno+1, 'OMG TABS!!!1'
|
|
||||||
if line[:-1].rstrip(' \t') != line[:-1]:
|
|
||||||
yield lno+1, 'trailing whitespace'
|
|
||||||
|
|
||||||
|
|
||||||
@checker('.rst', severity=0)
|
|
||||||
def check_line_length(fn, lines):
|
|
||||||
"""Check for line length; this checker is not run by default."""
|
|
||||||
for lno, line in enumerate(lines):
|
|
||||||
if len(line) > 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))
|
|
|
@ -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,<py: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<head>\n"
|
|
||||||
library/urllib.request,,:password,"""joe:password@python.org"""
|
|
||||||
library/urllib.parse,,:scheme,<URL:scheme://host/path>
|
|
||||||
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=<encoding-name>
|
|
||||||
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('<IIIHH', data[start:start+16])"
|
|
||||||
tutorial/stdlib2,,:start,filename = data[start:start+filenamesize]
|
|
||||||
tutorial/stdlib2,,:Warning,WARNING:root:Warning:config file server.conf not found
|
|
||||||
using/cmdline,,:errorhandler,:errorhandler
|
|
||||||
using/cmdline,,:message,action:message:category:module:lineno
|
|
||||||
using/cmdline,,:category,action:message:category:module:lineno
|
|
||||||
using/cmdline,,:module,action:message:category:module:lineno
|
|
||||||
using/cmdline,,:lineno,action:message:category:module:lineno
|
|
||||||
using/cmdline,,::,-W ignore::DeprecationWarning
|
|
||||||
using/unix,,:Packaging,https://en.opensuse.org/Portal:Packaging
|
|
||||||
whatsnew/2.0,,:len,
|
|
||||||
whatsnew/2.3,,::,
|
|
||||||
whatsnew/2.3,,:config,
|
|
||||||
whatsnew/2.3,,:Critical,
|
|
||||||
whatsnew/2.3,,:Error,
|
|
||||||
whatsnew/2.3,,:Problem,
|
|
||||||
whatsnew/2.3,,:root,
|
|
||||||
whatsnew/2.3,,:Warning,
|
|
||||||
whatsnew/2.4,,::,
|
|
||||||
whatsnew/2.4,,:System,
|
|
||||||
whatsnew/2.5,,:memory,:memory:
|
|
||||||
whatsnew/2.5,,:step,[start:stop:step]
|
|
||||||
whatsnew/2.5,,:stop,[start:stop:step]
|
|
||||||
whatsnew/2.7,,::,"ParseResult(scheme='http', netloc='[1080::8:800:200C:417A]',"
|
|
||||||
whatsnew/2.7,,::,>>> 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,"<actors xmlns:fictional=""http://characters.example.com"""
|
|
||||||
library/xml.etree.elementtree,,:character,<fictional:character>Lancelot</fictional:character>
|
|
||||||
library/xml.etree.elementtree,,:character,<fictional:character>Archie Leach</fictional:character>
|
|
||||||
library/xml.etree.elementtree,,:character,<fictional:character>Sir Robin</fictional:character>
|
|
||||||
library/xml.etree.elementtree,,:character,<fictional:character>Gunther</fictional:character>
|
|
||||||
library/xml.etree.elementtree,,:character,<fictional:character>Commander Clement</fictional:character>
|
|
||||||
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,<document xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
library/xml.etree.elementtree,,:include, <xi:include href="source.xml" parse="xml" />
|
|
||||||
library/xml.etree.elementtree,,:include, Copyright (c) <xi:include href="year.txt" parse="text" />.
|
|
||||||
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
|
|
Can't render this file because it contains an unexpected character in line 353 and column 55.
|
|
@ -468,6 +468,11 @@ Removed
|
||||||
* ``importlib.util.set_package`` has been removed.
|
* ``importlib.util.set_package`` has been removed.
|
||||||
(Contributed by Brett Cannon in :gh:`65961`.)
|
(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
|
||||||
|
<https://github.com/sphinx-contrib/sphinx-lint>`_.
|
||||||
|
(Contributed by Julien Palard in :gh:`98179`.)
|
||||||
|
|
||||||
|
|
||||||
Porting to Python 3.12
|
Porting to Python 3.12
|
||||||
======================
|
======================
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Deprecated tools ``make suspicious`` and ``rstlint.py`` are now removed.
|
||||||
|
They have been replaced by `spinx-lint
|
||||||
|
<https://pypi.org/project/sphinx-lint/>`_.
|
Loading…
Reference in New Issue